Add Git Code Hosting to Drone #3364

LET'S.GO.[DRONE](https://www.drone.io/).[GITNESSSSSS](https://gitness.com/)!!! <3
jobatzil/fix/autolicense
Johannes Batzill 2023-09-21 12:28:15 -07:00 committed by GitHub
commit 6c0a9044f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2476 changed files with 191844 additions and 72041 deletions

View File

@ -1,2 +1,12 @@
*
!release/*
*.sqlite
*.sqlite3
web/node_modules
web/dist
release
.idea
coverage.out
# ignore any executables we build
/gitness
/gitrpcserver
/gitness-githook

View File

@ -1,107 +0,0 @@
---
kind: pipeline
type: docker
name: linux-amd64
platform:
arch: amd64
os: linux
steps:
- name: test
image: golang:1.14.15
commands:
- go test -race ./...
- go build -o /dev/null github.com/drone/drone/cmd/drone-server
- go build -o /dev/null -tags "oss nolimit" github.com/drone/drone/cmd/drone-server
- name: build
image: golang:1.14.15
commands:
- sh scripts/build.sh
environment:
GOARCH: amd64
GOOS: linux
- name: publish
image: plugins/docker:18
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
dockerfile: docker/Dockerfile.server.linux.amd64
repo: drone/drone
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
event:
- push
- tag
---
kind: pipeline
type: vm
name: linux-arm64
pool:
use: ubuntu_arm64
platform:
arch: arm64
os: linux
steps:
- name: build
image: golang:1.14.15
commands:
- sh scripts/build.sh
environment:
GOARCH: arm64
GOOS: linux
- name: publish
image: plugins/docker:18
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
dockerfile: docker/Dockerfile.server.linux.arm64
repo: drone/drone
username:
from_secret: docker_username
password:
from_secret: docker_password
trigger:
event:
- push
- tag
depends_on:
- linux-amd64
---
kind: pipeline
type: docker
name: manifest
steps:
- name: publish
image: plugins/manifest:1.2
settings:
auto_tag: true
ignore_missing: true
spec: docker/manifest.server.tmpl
username:
from_secret: docker_username
password:
from_secret: docker_password
trigger:
event:
- push
- tag
depends_on:
- linux-arm64

7
.github/readme.md vendored
View File

@ -1,7 +0,0 @@
Gitness is an Open Source developer platform with Source Control management, Continuous Integration and Continuous Delivery. Gitness is the successor to Drone and will be merging with the Drone project over the coming months.
Documentation and Other Links:
* Setup Documentation [docs.gitness.com/getting-started](https://docs.gitness.com/)
* Usage Documentation for repositories [docs.drone.io/getting-started](https://docs.gitness.com/repositories/overview)
* Join the [Gitness Slack Channel](https://join.slack.com/t/harnesscommunity/shared_invite/zt-y4hdqh7p-RVuEQyIl5Hcx4Ck8VCvzBw)

View File

@ -1,3 +0,0 @@
since-tag=v2.0.4
issues=false

28
.gitignore vendored
View File

@ -1,13 +1,21 @@
.vscode
.DS_Store
NOTES*
__debug_bin
*.sqlite
*.txt
*.out
*.key
_research
.env
.env.*
release/
scripts/*.go
docker/**/data
TODO*
*.sqlite
*.sqlite3
web/node_modules
web/dist
web/coverage
yarn-error*
release
.idea
.vscode/settings.json
coverage.out
gitness.session.sql
# ignore any executables we build
/gitness
/gitrpcserver
/gitness-githook

322
.golangci.yml Normal file
View File

@ -0,0 +1,322 @@
## Golden config for golangci-lint v1.49.0
run:
# Timeout for analysis, e.g. 30s, 5m.
# Default: 1m
timeout: 3m
# This file contains only configs which differ from defaults.
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
linters-settings:
cyclop:
# The maximal code complexity to report.
# Default: 10
max-complexity: 30
# The maximal average package complexity.
# If it's higher than 0.0 (float) the check is enabled
# Default: 0.0
package-average: 10.0
errcheck:
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
# Such cases aren't reported by default.
# Default: false
check-type-assertions: true
funlen:
# Checks the number of lines in a function.
# If lower than 0, disable the check.
# Default: 60
lines: 100
# Checks the number of statements in a function.
# If lower than 0, disable the check.
# Default: 40
statements: 50
gocognit:
# Minimal code complexity to report
# Default: 30 (but we recommend 10-20)
min-complexity: 20
gocritic:
# Settings passed to gocritic.
# The settings key is the name of a supported gocritic checker.
# The list of supported checkers can be find in https://go-critic.github.io/overview.
settings:
captLocal:
# Whether to restrict checker to params only.
# Default: true
paramsOnly: false
underef:
# Whether to skip (*x).method() calls where x is a pointer receiver.
# Default: true
skipRecvDeref: false
gomnd:
# List of function patterns to exclude from analysis.
# Values always ignored: `time.Date`
# Default: []
ignored-functions:
- os.Chmod
- os.Mkdir
- os.MkdirAll
- os.OpenFile
- os.WriteFile
- prometheus.ExponentialBuckets
- prometheus.ExponentialBucketsRange
- prometheus.LinearBuckets
- strconv.FormatFloat
- strconv.FormatInt
- strconv.FormatUint
- strconv.ParseFloat
- strconv.ParseInt
- strconv.ParseUint
gomodguard:
blocked:
# List of blocked modules.
# Default: []
modules:
- github.com/golang/protobuf:
recommendations:
- google.golang.org/protobuf
reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules"
- github.com/satori/go.uuid:
recommendations:
- github.com/google/uuid
reason: "satori's package is not maintained"
- github.com/gofrs/uuid:
recommendations:
- github.com/google/uuid
reason: "see recommendation from dev-infra team: https://confluence.gtforge.com/x/gQI6Aw"
govet:
# Enable all analyzers.
# Default: false
enable-all: true
# Disable analyzers by name.
# Run `go tool vet help` to see all analyzers.
# Default: []
disable:
- fieldalignment # too strict
# Settings per analyzer.
settings:
shadow:
# Whether to be strict about shadowing; can be noisy.
# Default: false
strict: true
nakedret:
# Make an issue if func has more lines of code than this setting, and it has naked returns.
# Default: 30
max-func-lines: 30
rowserrcheck:
# database/sql is always checked
# Default: []
packages:
- github.com/jmoiron/sqlx
tenv:
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
# Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
# Default: false
all: true
goheader:
# Supports two types 'const` and `regexp`.
# Values can be used recursively.
# Default: {}
values:
const:
# Define here const type values in format k:v.
# For example:
COMPANY: Harness Inc.
# The template use for checking.
# Default: ""
template: |-
Copyright 2023 Harness, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# As alternative of directive 'template', you may put the path to file with the template source.
# Useful if you need to load the template from a specific file.
# Default: ""
# template-path: /path/to/my/template.tmpl
gci:
# DEPRECATED: use `sections` and `prefix(github.com/org/project)` instead.
# local-prefixes: github.com/harness/gitness
# Section configuration to compare against.
# Section names are case-insensitive and may contain parameters in ().
# The default order of sections is `standard > default > custom > blank > dot`,
# If `custom-order` is `true`, it follows the order of `sections` option.
# Default: ["standard", "default"]
sections:
- standard # Standard section: captures all standard packages.
- prefix(github.com/harness/gitness) # Custom section: groups all imports with the specified Prefix.
- default # Default section: contains all imports that could not be matched to another section type.
- blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled.
- dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled.
# Skip generated files.
# Default: true
skip-generated: false
# Enable custom order of sections.
# If `true`, make the section order the same as the order of `sections`.
# Default: false
custom-order: true
tagliatelle:
# Check the struck tag name case.
case:
rules:
# Any struct tag type can be used.
# Support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
json: snake
db: snake
yaml: snake
xml: snake
bson: snake
avro: snake
mapstructure: snake
linters:
disable-all: true
enable:
## enabled by default
- errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases
- gosimple # specializes in simplifying a code
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # detects when assignments to existing variables are not used
- staticcheck # is a go vet on steroids, applying a ton of static analysis checks
- typecheck # like the front-end of a Go compiler, parses and type-checks Go code
- unused # checks for unused constants, variables, functions and types
## disabled by default
- asasalint # checks for pass []any as any in variadic func(...any)
- asciicheck # checks that your code does not contain non-ASCII identifiers
- bidichk # checks for dangerous unicode character sequences
- bodyclose # checks whether HTTP response body is closed successfully
#- contextcheck # checks the function whether use a non-inherited context # TODO: enable after golangci-lint uses https://github.com/sylvia7788/contextcheck/releases/tag/v1.0.7
- cyclop # checks function and package cyclomatic complexity
# - dupl # tool for code clone detection
- durationcheck # checks for two durations multiplied together
- errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error
- errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13
- execinquery # checks query string in Query function which reads your Go src files and warning it finds
- exhaustive # checks exhaustiveness of enum switch statements
- exportloopref # checks for pointers to enclosing loop variables
- forbidigo # forbids identifiers
#- funlen # tool for detection of long functions
#- gochecknoglobals # checks that no global variables exist
#- gochecknoinits # checks that no init functions are present in Go code
- gocognit # computes and checks the cognitive complexity of functions
- goconst # finds repeated strings that could be replaced by a constant
- gocritic # provides diagnostics that check for bugs, performance and style issues
- gocyclo # computes and checks the cyclomatic complexity of functions
- godot # checks if comments end in a period
- goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt
- gomnd # detects magic numbers
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
- gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations
- goprintffuncname # checks that printf-like functions are named with f at the end
- gosec # inspects source code for security problems
- lll # reports long lines
- makezero # finds slice declarations with non-zero initial length
- nakedret # finds naked returns in functions greater than a specified function length
- nestif # reports deeply nested if statements
- nilerr # finds the code that returns nil even if it checks that the error is not nil
- nilnil # checks that there is no simultaneous return of nil error and an invalid value
- noctx # finds sending http request without context.Context
# - nolintlint # reports ill-formed or insufficient nolint directives
# - nonamedreturns # reports all named returns
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
- predeclared # finds code that shadows one of Go's predeclared identifiers
- promlinter # checks Prometheus metrics naming via promlint
- reassign # checks that package variables are not reassigned
- revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint
- rowserrcheck # checks whether Err of rows is checked successfully
- sqlclosecheck # checks that sql.Rows and sql.Stmt are closed
- stylecheck # is a replacement for golint
- tagliatelle # checks the struct tags
- tenv # detects using os.Setenv instead of t.Setenv since Go1.17
#- testpackage # makes you use a separate _test package
- tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes
- unconvert # removes unnecessary type conversions
- unparam # reports unused function parameters
- usestdlibvars # detects the possibility to use variables/constants from the Go standard library
- wastedassign # finds wasted assignment statements
- whitespace # detects leading and trailing whitespace
## you may want to enable
#- decorder # checks declaration order and count of types, constants, variables and functions
#- exhaustruct # checks if all structure fields are initialized
- gci # controls golang package import order and makes it always deterministic
#- godox # detects FIXME, TODO and other comment keywords
- goheader # checks is file header matches to pattern
#- interfacebloat # checks the number of methods inside an interface
#- ireturn # accept interfaces, return concrete types
#- prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated
#- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope
#- wrapcheck # checks that errors returned from external packages are wrapped
## disabled
#- containedctx # detects struct contained context.Context field
#- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages
#- dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
#- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted
#- forcetypeassert # [replaced by errcheck] finds forced type assertions
#- goerr113 # [too strict] checks the errors handling expressions
#- gofmt # [replaced by goimports] checks whether code was gofmt-ed
#- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed
#- grouper # analyzes expression groups
#- importas # enforces consistent import aliases
#- logrlint # [owner archived repository] checks logr arguments
#- maintidx # measures the maintainability index of each function
- misspell # [useless] finds commonly misspelled English words in comments
#- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity
#- paralleltest # [too many false positives] detects missing usage of t.Parallel() method in your Go test
#- thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers
#- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines
issues:
# Maximum count of issues with the same text.
# Set to 0 to disable.
# Default: 3
max-same-issues: 50
exclude-rules:
- text: 'shadow: declaration of "(err|ctx)" shadows declaration at'
linters: [ govet ]
- source: "^//\\s*go:generate\\s"
linters: [ lll ]
- source: "(noinspection|TODO)"
linters: [ godot ]
- source: "//noinspection"
linters: [ gocritic ]
- source: "^\\s+if _, ok := err\\.\\([^.]+\\.InternalError\\); ok {"
linters: [ errorlint ]
- path: "^cli/"
linters: [forbidigo]
- text: "mnd: Magic number: \\d"
linters:
- gomnd
- path: "_test\\.go"
linters:
- bodyclose
- dupl
- funlen
- goconst
- gosec
- noctx
- wrapcheck

4
.local.env Normal file
View File

@ -0,0 +1,4 @@
GITNESS_TRACE=true
GITNESS_WEBHOOK_ALLOW_LOOPBACK=true
GITNESS_PRINCIPAL_ADMIN_PASSWORD=changeit
GITNESS_METRIC_ENABLED=false

View File

@ -1,11 +0,0 @@
1. Clone the repository
2. Install go 1.11 or later with Go modules enabled
3. Install binaries to $GOPATH/bin
go install github.com/drone/drone/cmd/drone-server
4. Start the server at localhost:8080
export DRONE_GITHUB_CLIENT_ID=...
export DRONE_GITHUB_CLIENT_SECRET=...
drone-server

View File

@ -1,11 +0,0 @@
1. Clone the repository
2. Install go 1.11 or later with Go modules enabled
3. Install binaries to $GOPATH/bin
go install -tags "oss nolimit" github.com/drone/drone/cmd/drone-server
4. Start the server at localhost:8080
export DRONE_GITHUB_CLIENT_ID=...
export DRONE_GITHUB_CLIENT_SECRET=...
drone-server

View File

@ -1,797 +0,0 @@
# Changelog
## [v2.20.0](https://github.com/harness/drone/tree/v2.20.0) (2023-08-21)
[Full Changelog](https://github.com/harness/drone/compare/v2.19.0...v2.20.0)
**Implemented enhancements:**
- + sync gitea redirecturl config from gitee for customize login redire… [\#3319](https://github.com/harness/drone/pull/3319) ([fireinice](https://github.com/fireinice))
**Fixed bugs:**
- \(CI-8780\) set approved stages to waiting, if they have stage depende… [\#3355](https://github.com/harness/drone/pull/3355) ([tphoney](https://github.com/tphoney))
## [v2.19.0](https://github.com/harness/drone/tree/v2.19.0) (2023-08-15)
[Full Changelog](https://github.com/harness/drone/compare/scheduler_experiment...v2.19.0)
**Implemented enhancements:**
- Support arbitrary action value from parameter in query string [\#3341](https://github.com/harness/drone/pull/3341) ([filippopisano](https://github.com/filippopisano))
**Fixed bugs:**
- bump drone-ui to 2.11.5 [\#3350](https://github.com/harness/drone/pull/3350) ([d1wilko](https://github.com/d1wilko))
- bump drone-ui to 2.11.4 [\#3349](https://github.com/harness/drone/pull/3349) ([d1wilko](https://github.com/d1wilko))
- \(fix\) prevent scheduler deadlock [\#3344](https://github.com/harness/drone/pull/3344) ([tphoney](https://github.com/tphoney))
- bump drone-ui to 2.11.3 [\#3337](https://github.com/harness/drone/pull/3337) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\) prep for v2.19.0 [\#3352](https://github.com/harness/drone/pull/3352) ([tphoney](https://github.com/tphoney))
- remove repetitive words [\#3342](https://github.com/harness/drone/pull/3342) ([cuishuang](https://github.com/cuishuang))
- Revert "fix scheduler queue deadlock" [\#3331](https://github.com/harness/drone/pull/3331) ([tphoney](https://github.com/tphoney))
## [scheduler_experiment](https://github.com/harness/drone/tree/scheduler_experiment) (2023-07-05)
[Full Changelog](https://github.com/harness/drone/compare/v2.18.0...scheduler_experiment)
**Fixed bugs:**
- fix scheduler queue deadlock [\#3330](https://github.com/harness/drone/pull/3330) ([tphoney](https://github.com/tphoney))
## [v2.18.0](https://github.com/harness/drone/tree/v2.18.0) (2023-07-04)
[Full Changelog](https://github.com/harness/drone/compare/v2.17.0...v2.18.0)
**Implemented enhancements:**
- support custom pipeline message [\#3294](https://github.com/harness/drone/pull/3294) ([zc2638](https://github.com/zc2638))
**Fixed bugs:**
- bump drone-ui to 2.11.2 [\#3327](https://github.com/harness/drone/pull/3327) ([d1wilko](https://github.com/d1wilko))
- Fix comment errors [\#3302](https://github.com/harness/drone/pull/3302) ([weidongkl](https://github.com/weidongkl))
**Merged pull requests:**
- v2.18.0 release prep [\#3328](https://github.com/harness/drone/pull/3328) ([tphoney](https://github.com/tphoney))
## [v2.17.0](https://github.com/harness/drone/tree/v2.17.0) (2023-04-25)
[Full Changelog](https://github.com/harness/drone/compare/v2.16.0...v2.17.0)
**Implemented enhancements:**
- Add `authtype` to logging middleware [\#3310](https://github.com/harness/drone/pull/3310) ([colinhoglund](https://github.com/colinhoglund))
- Add config for the buffer [\#3308](https://github.com/harness/drone/pull/3308) ([TheJokersThief](https://github.com/TheJokersThief))
**Fixed bugs:**
- store/card: fix dropped error [\#3300](https://github.com/harness/drone/pull/3300) ([alrs](https://github.com/alrs))
- bump drone-ui to 2.9.1 [\#3298](https://github.com/harness/drone/pull/3298) ([d1wilko](https://github.com/d1wilko))
- Starlark: Update `go.starlark.net` dependency [\#3284](https://github.com/harness/drone/pull/3284) ([dsotirakis](https://github.com/dsotirakis))
**Merged pull requests:**
- release prep for v2.17.0 [\#3316](https://github.com/harness/drone/pull/3316) ([eoinmcafee00](https://github.com/eoinmcafee00))
- bump drone-ui to 2.11.1 [\#3315](https://github.com/harness/drone/pull/3315) ([d1wilko](https://github.com/d1wilko))
- bump drone-ui to 2.11.0 [\#3313](https://github.com/harness/drone/pull/3313) ([d1wilko](https://github.com/d1wilko))
- bump drone-ui to 2.10.0 [\#3311](https://github.com/harness/drone/pull/3311) ([d1wilko](https://github.com/d1wilko))
- \(maint\) move to use the arm64 pool [\#3296](https://github.com/harness/drone/pull/3296) ([tphoney](https://github.com/tphoney))
## [v2.16.0](https://github.com/harness/drone/tree/v2.16.0) (2022-12-15)
[Full Changelog](https://github.com/harness/drone/compare/v2.15.0...v2.16.0)
**Implemented enhancements:**
- Make Starlark file size limit configurable [\#3291](https://github.com/harness/drone/pull/3291) ([andrii-kasparevych](https://github.com/andrii-kasparevych))
- Enhance status check label for promotions [\#3263](https://github.com/harness/drone/pull/3263) ([michelangelomo](https://github.com/michelangelomo))
**Fixed bugs:**
- \(bugfix\) bump go-scm to v1.28.0 [\#3290](https://github.com/harness/drone/pull/3290) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- \(maint\) 2.16.0 release prep [\#3295](https://github.com/harness/drone/pull/3295) ([tphoney](https://github.com/tphoney))
## [v2.15.0](https://github.com/harness/drone/tree/v2.15.0) (2022-10-28)
[Full Changelog](https://github.com/harness/drone/compare/v2.14.0...v2.15.0)
**Implemented enhancements:**
- bump ui version [\#3279](https://github.com/harness/drone/pull/3279) ([d1wilko](https://github.com/d1wilko))
- Add endpoint for allowing admins to force rotate a user's token [\#3272](https://github.com/harness/drone/pull/3272) ([ShiftedMr](https://github.com/ShiftedMr))
**Merged pull requests:**
- release prep v2.15.0 [\#3281](https://github.com/harness/drone/pull/3281) ([d1wilko](https://github.com/d1wilko))
## [v2.14.0](https://github.com/harness/drone/tree/v2.14.0) (2022-10-18)
[Full Changelog](https://github.com/harness/drone/compare/v2.13.0...v2.14.0)
**Implemented enhancements:**
- \(DRON-418\) send webhook and set status for failed builds [\#3266](https://github.com/harness/drone/pull/3266) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- v2.14.0 release prep [\#3275](https://github.com/harness/drone/pull/3275) ([d1wilko](https://github.com/d1wilko))
## [v2.13.0](https://github.com/harness/drone/tree/v2.13.0) (2022-09-21)
[Full Changelog](https://github.com/harness/drone/compare/v2.12.1...v2.13.0)
**Implemented enhancements:**
- feat: update drone-yaml module [\#3249](https://github.com/harness/drone/pull/3249) ([jimsheldon](https://github.com/jimsheldon))
- support time zone [\#3241](https://github.com/harness/drone/pull/3241) ([zc2638](https://github.com/zc2638))
**Fixed bugs:**
- update discourse.drone.io to community.harness.io [\#3261](https://github.com/harness/drone/pull/3261) ([kit101](https://github.com/kit101))
- \(DRON-392\) cascade deletes on purge [\#3243](https://github.com/harness/drone/pull/3243) ([tphoney](https://github.com/tphoney))
- Template converter, don't skip .yaml extension. [\#3242](https://github.com/harness/drone/pull/3242) ([staffanselander](https://github.com/staffanselander))
**Merged pull requests:**
- v2.13.0 release prep [\#3268](https://github.com/harness/drone/pull/3268) ([tphoney](https://github.com/tphoney))
- \(maint\) disable arm builds [\#3262](https://github.com/harness/drone/pull/3262) ([tphoney](https://github.com/tphoney))
- Update links to discourse in issue template [\#3233](https://github.com/harness/drone/pull/3233) ([alikhil](https://github.com/alikhil))
## [v2.12.1](https://github.com/harness/drone/tree/v2.12.1) (2022-06-15)
[Full Changelog](https://github.com/harness/drone/compare/v2.12.0...v2.12.1)
**Fixed bugs:**
- \(bug\) - fix original template scripts & remove amend scripts [\#3229](https://github.com/harness/drone/pull/3229) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(bug\) - remove unique index on template name [\#3226](https://github.com/harness/drone/pull/3226) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Added OAuth2 token refresher for Gitlab [\#3215](https://github.com/harness/drone/pull/3215) ([EndymionWight](https://github.com/EndymionWight))
**Merged pull requests:**
- release prep for v2.12.1 [\#3232](https://github.com/harness/drone/pull/3232) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(maint\) fix starlark test on windows [\#3230](https://github.com/harness/drone/pull/3230) ([tphoney](https://github.com/tphoney))
- \(maint\) fix unit tests so they pass on windows [\#3228](https://github.com/harness/drone/pull/3228) ([tphoney](https://github.com/tphoney))
- Update Readme to Fix Typo [\#3223](https://github.com/harness/drone/pull/3223) ([hrittikhere](https://github.com/hrittikhere))
- \(bug\) add unit test for comments in template file [\#3221](https://github.com/harness/drone/pull/3221) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Bump scm version to v1.24.0 [\#3219](https://github.com/harness/drone/pull/3219) ([kit101](https://github.com/kit101))
## [v2.12.0](https://github.com/harness/drone/tree/v2.12.0) (2022-05-16)
[Full Changelog](https://github.com/harness/drone/compare/v2.11.1...v2.12.0)
**Implemented enhancements:**
- bump SCM version to v1.21.1 [\#3204](https://github.com/harness/drone/pull/3204) ([d1wilko](https://github.com/d1wilko))
- bump ui version [\#3202](https://github.com/harness/drone/pull/3202) ([d1wilko](https://github.com/d1wilko))
**Fixed bugs:**
- \(fix\) update drone ui to 2.8.2 [\#3211](https://github.com/harness/drone/pull/3211) ([tphoney](https://github.com/tphoney))
- \(dron-267\) correctly set parent for promotion retry [\#3210](https://github.com/harness/drone/pull/3210) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- release prep v2.12.0 [\#3214](https://github.com/harness/drone/pull/3214) ([tphoney](https://github.com/tphoney))
- fixing URL [\#3208](https://github.com/harness/drone/pull/3208) ([dnielsen](https://github.com/dnielsen))
- update community information with updated links [\#3199](https://github.com/harness/drone/pull/3199) ([mrsantons](https://github.com/mrsantons))
## [v2.11.1](https://github.com/harness/drone/tree/v2.11.1) (2022-03-15)
[Full Changelog](https://github.com/harness/drone/compare/v2.11.0...v2.11.1)
**Fixed bugs:**
- ignore nil repos in list and add better debugging [\#3196](https://github.com/harness/drone/pull/3196) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\) release prep for 2.11.1 [\#3197](https://github.com/harness/drone/pull/3197) ([d1wilko](https://github.com/d1wilko))
## [v2.11.0](https://github.com/harness/drone/tree/v2.11.0) (2022-03-08)
[Full Changelog](https://github.com/harness/drone/compare/v2.10.0...v2.11.0)
**Implemented enhancements:**
- bump UI and SCM versions [\#3193](https://github.com/harness/drone/pull/3193) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\) release prep for 2.11.0 [\#3194](https://github.com/harness/drone/pull/3194) ([d1wilko](https://github.com/d1wilko))
## [v2.10.0](https://github.com/harness/drone/tree/v2.10.0) (2022-03-03)
[Full Changelog](https://github.com/harness/drone/compare/v2.9.1...v2.10.0)
**Implemented enhancements:**
- bump UI version to v2.7.0 [\#3190](https://github.com/harness/drone/pull/3190) ([d1wilko](https://github.com/d1wilko))
- bump UI version to v2.6.2 [\#3188](https://github.com/harness/drone/pull/3188) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\) release prep for 2.10.0 [\#3191](https://github.com/harness/drone/pull/3191) ([d1wilko](https://github.com/d1wilko))
## [v2.9.1](https://github.com/harness/drone/tree/v2.9.1) (2022-01-27)
[Full Changelog](https://github.com/harness/drone/compare/v2.9.0...v2.9.1)
**Fixed bugs:**
- bump ui version 2.6.1 [\#3185](https://github.com/harness/drone/pull/3185) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\) release prep for 2.9.1 [\#3186](https://github.com/harness/drone/pull/3186) ([tphoney](https://github.com/tphoney))
## [v2.9.0](https://github.com/harness/drone/tree/v2.9.0) (2022-01-26)
[Full Changelog](https://github.com/harness/drone/compare/v2.8.0...v2.9.0)
**Implemented enhancements:**
- bump ui to v2.6.0 [\#3183](https://github.com/harness/drone/pull/3183) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Merged pull requests:**
- release prep for v2.9.0 [\#3184](https://github.com/harness/drone/pull/3184) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.8.0](https://github.com/harness/drone/tree/v2.8.0) (2022-01-11)
[Full Changelog](https://github.com/harness/drone/compare/v2.7.3...v2.8.0)
**Implemented enhancements:**
- bump UI to v2.5.0 [\#3180](https://github.com/harness/drone/pull/3180) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(feat\) ignore archive repos on sync [\#3178](https://github.com/harness/drone/pull/3178) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Datadog add the tag of 'remote:gitee' [\#3174](https://github.com/harness/drone/pull/3174) ([kit101](https://github.com/kit101))
- Add tag filter when call build list endpoint [\#3173](https://github.com/harness/drone/pull/3173) ([michelangelomo](https://github.com/michelangelomo))
**Fixed bugs:**
- \(maint\) add warning around typo for stage\_id in step struct [\#3179](https://github.com/harness/drone/pull/3179) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- release prep v2.8.0 [\#3181](https://github.com/harness/drone/pull/3181) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.7.3](https://github.com/harness/drone/tree/v2.7.3) (2021-12-30)
[Full Changelog](https://github.com/harness/drone/compare/v2.7.2...v2.7.3)
**Fixed bugs:**
- bump go-scm to v1.16.3 [\#3175](https://github.com/harness/drone/pull/3175) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Merged pull requests:**
- release prep v2.7.3 [\#3176](https://github.com/harness/drone/pull/3176) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.7.2](https://github.com/harness/drone/tree/v2.7.2) (2021-12-19)
[Full Changelog](https://github.com/harness/drone/compare/v2.7.1...v2.7.2)
**Implemented enhancements:**
- bump go-scm to v1.16.2 [\#3169](https://github.com/harness/drone/pull/3169) ([kit101](https://github.com/kit101))
**Fixed bugs:**
- fixbug gitee provide refresher [\#3168](https://github.com/harness/drone/pull/3168) ([kit101](https://github.com/kit101))
**Merged pull requests:**
- release prep 2.7.2 [\#3172](https://github.com/harness/drone/pull/3172) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.7.1](https://github.com/harness/drone/tree/v2.7.1) (2021-12-17)
[Full Changelog](https://github.com/harness/drone/compare/v2.7.0...v2.7.1)
**Fixed bugs:**
- fixes issue with redirects on double slashes in url [\#3170](https://github.com/harness/drone/pull/3170) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Merged pull requests:**
- release prep v2.7.1 [\#3171](https://github.com/harness/drone/pull/3171) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.7.0](https://github.com/harness/drone/tree/v2.7.0) (2021-12-15)
[Full Changelog](https://github.com/harness/drone/compare/v2.6.0...v2.7.0)
**Implemented enhancements:**
- bump UI to v2.4.1 [\#3167](https://github.com/harness/drone/pull/3167) ([d1wilko](https://github.com/d1wilko))
**Fixed bugs:**
- \(DRON-157\) use deploy string in deployment [\#3165](https://github.com/harness/drone/pull/3165) ([tphoney](https://github.com/tphoney))
**Merged pull requests:**
- release v2.7.0 [\#3166](https://github.com/harness/drone/pull/3166) ([d1wilko](https://github.com/d1wilko))
## [v2.6.0](https://github.com/harness/drone/tree/v2.6.0) (2021-11-30)
[Full Changelog](https://github.com/harness/drone/compare/v2.5.0...v2.6.0)
**Implemented enhancements:**
- Feat: implemented gitee client [\#3156](https://github.com/harness/drone/pull/3156) ([kit101](https://github.com/kit101))
**Merged pull requests:**
- release prep for v2.6.0 [\#3163](https://github.com/harness/drone/pull/3163) ([tphoney](https://github.com/tphoney))
## [v2.5.0](https://github.com/harness/drone/tree/v2.5.0) (2021-11-17)
[Full Changelog](https://github.com/harness/drone/compare/v2.4.0...v2.5.0)
**Implemented enhancements:**
- bump ui to v2.4.0 [\#3160](https://github.com/harness/drone/pull/3160) ([eoinmcafee00](https://github.com/eoinmcafee00))
- add new endpoint for uploading cards [\#3159](https://github.com/harness/drone/pull/3159) ([eoinmcafee00](https://github.com/eoinmcafee00))
- refactor create / find / delete end points for cards [\#3158](https://github.com/harness/drone/pull/3158) ([eoinmcafee00](https://github.com/eoinmcafee00))
- bump ui to v2.3.1 [\#3155](https://github.com/harness/drone/pull/3155) ([d1wilko](https://github.com/d1wilko))
- provide ability to create/read/store card data in drone server [\#3149](https://github.com/harness/drone/pull/3149) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(DRON-124\) adding new status endpoint [\#3143](https://github.com/harness/drone/pull/3143) ([tphoney](https://github.com/tphoney))
**Fixed bugs:**
- fix a typo in readme [\#3150](https://github.com/harness/drone/pull/3150) ([nothatDinger](https://github.com/nothatDinger))
**Merged pull requests:**
- release prep for v2.5.0 [\#3161](https://github.com/harness/drone/pull/3161) ([eoinmcafee00](https://github.com/eoinmcafee00))
## [v2.4.0](https://github.com/harness/drone/tree/v2.4.0) (2021-09-23)
[Full Changelog](https://github.com/harness/drone/compare/v2.3.1...v2.4.0)
**Implemented enhancements:**
- bump ui version to v2.3.0 [\#3146](https://github.com/harness/drone/pull/3146) ([d1wilko](https://github.com/d1wilko))
- verify if the application is buildable [\#3144](https://github.com/harness/drone/pull/3144) ([marko-gacesa](https://github.com/marko-gacesa))
**Fixed bugs:**
- fixes build issue with bitbucket cloud [\#3147](https://github.com/harness/drone/pull/3147) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Fix stepLimit param in Starlark and Template OSS code [\#3141](https://github.com/harness/drone/pull/3141) ([phil-davis](https://github.com/phil-davis))
- fix a broken link in readme [\#3140](https://github.com/harness/drone/pull/3140) ([empire](https://github.com/empire))
**Merged pull requests:**
- \(maint\)-release 2.4.0 [\#3148](https://github.com/harness/drone/pull/3148) ([d1wilko](https://github.com/d1wilko))
- Allow jsonnet imports in pipeline configuration [\#3105](https://github.com/harness/drone/pull/3105) ([hhamalai](https://github.com/hhamalai))
## [v2.3.1](https://github.com/harness/drone/tree/v2.3.1) (2021-09-09)
[Full Changelog](https://github.com/harness/drone/compare/v2.3.0...v2.3.1)
**Implemented enhancements:**
- bump ui to v2.2.1 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3138](https://github.com/harness/drone/pull/3138) ([d1wilko](https://github.com/d1wilko))
**Merged pull requests:**
- \(maint\)-release 2.3.1 [\#3139](https://github.com/harness/drone/pull/3139) ([d1wilko](https://github.com/d1wilko))
## [v2.3.0](https://github.com/harness/drone/tree/v2.3.0) (2021-09-09)
[Full Changelog](https://github.com/harness/drone/compare/v2.2.0...v2.3.0)
**Implemented enhancements:**
- bump ui to v2.2.0 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3137](https://github.com/harness/drone/pull/3137) ([d1wilko](https://github.com/d1wilko))
- Make starlark step limit configurable [\#3134](https://github.com/harness/drone/pull/3134) ([phil-davis](https://github.com/phil-davis))
- \(feat\) drone h/a: wrapped scheduler's signal func with redis mutex [\#3130](https://github.com/harness/drone/pull/3130) ([marko-gacesa](https://github.com/marko-gacesa))
**Fixed bugs:**
- \(fix\) trim http/s prefixes from config hostnames [\#3136](https://github.com/harness/drone/pull/3136) ([tphoney](https://github.com/tphoney))
- \(fix\) remove unused jwt-go library [\#3129](https://github.com/harness/drone/pull/3129) ([tphoney](https://github.com/tphoney))
## [v2.2.0](https://github.com/harness/drone/tree/v2.2.0) (2021-09-01)
[Full Changelog](https://github.com/harness/drone/compare/v2.1.0...v2.2.0)
**Implemented enhancements:**
- \(maint\) ui version v2.1.0 - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3132](https://github.com/harness/drone/pull/3132) ([d1wilko](https://github.com/d1wilko))
- Ability to cancel running builds, if a new commit is pushed [\#3126](https://github.com/harness/drone/pull/3126) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Fixed bugs:**
- fix templating reg expression to match if .drone.yml contains --- characters [\#3131](https://github.com/harness/drone/pull/3131) ([eoinmcafee00](https://github.com/eoinmcafee00))
- add check on template extension type - throw error if invalid [\#3128](https://github.com/harness/drone/pull/3128) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Merged pull requests:**
- \(maint\)-release 2.2.0 [\#3133](https://github.com/harness/drone/pull/3133) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Rename files with camelCase name to use snake\_case convention [\#3127](https://github.com/harness/drone/pull/3127) ([marko-gacesa](https://github.com/marko-gacesa))
- event-stream supports timeout [\#3125](https://github.com/harness/drone/pull/3125) ([zc2638](https://github.com/zc2638))
- \(maint\) Readme update Add Contributor Section [\#3111](https://github.com/harness/drone/pull/3111) ([mrsantons](https://github.com/mrsantons))
## [v2.1.0](https://github.com/harness/drone/tree/v2.1.0) (2021-08-24)
[Full Changelog](https://github.com/harness/drone/compare/v2.0.6...v2.1.0)
**Implemented enhancements:**
- \(maint\) ui version v2.0.1. - https://github.com/drone/drone-ui/blob/main/CHANGELOG.md [\#3123](https://github.com/harness/drone/pull/3123) ([d1wilko](https://github.com/d1wilko))
- add support for yaml templates [\#3120](https://github.com/harness/drone/pull/3120) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Fixed bugs:**
- Update error message to forbidden if user membership doesn't exist on repo [\#3122](https://github.com/harness/drone/pull/3122) ([eoinmcafee00](https://github.com/eoinmcafee00))
- update create template path to have namespace, instead of inside the payload [\#3121](https://github.com/harness/drone/pull/3121) ([eoinmcafee00](https://github.com/eoinmcafee00))
- update dependency drone/go-scm to 1.15.2 to fix gitea build problem [\#3118](https://github.com/harness/drone/pull/3118) ([sesky4](https://github.com/sesky4))
**Merged pull requests:**
- \(maint\) v2.1.0 release prep [\#3124](https://github.com/harness/drone/pull/3124) ([d1wilko](https://github.com/d1wilko))
## [v2.0.6](https://github.com/harness/drone/tree/v2.0.6) (2021-08-17)
[Full Changelog](https://github.com/harness/drone/compare/v2.0.5...v2.0.6)
**Merged pull requests:**
- \(maint\) v2.0.6 release prep [\#3119](https://github.com/harness/drone/pull/3119) ([tphoney](https://github.com/tphoney))
## [v2.0.5](https://github.com/harness/drone/tree/v2.0.5) (2021-08-17)
[Full Changelog](https://github.com/harness/drone/compare/v2.0.4...v2.0.5)
**Implemented enhancements:**
- bump ui version [\#3115](https://github.com/harness/drone/pull/3115) ([d1wilko](https://github.com/d1wilko))
- bump ui version [\#3114](https://github.com/harness/drone/pull/3114) ([d1wilko](https://github.com/d1wilko))
- Add support for nested data objects within templates [\#3110](https://github.com/harness/drone/pull/3110) ([eoinmcafee00](https://github.com/eoinmcafee00))
- \(feat\) redis implementation for pub-sub, log streaming and canceller [\#3108](https://github.com/harness/drone/pull/3108) ([marko-gacesa](https://github.com/marko-gacesa))
**Fixed bugs:**
- fix issue where map changes order therefore test randomly fails [\#3112](https://github.com/harness/drone/pull/3112) ([eoinmcafee00](https://github.com/eoinmcafee00))
**Merged pull requests:**
- release 2.0.5 [\#3117](https://github.com/harness/drone/pull/3117) ([eoinmcafee00](https://github.com/eoinmcafee00))
- Update pull\_request\_template.md [\#3107](https://github.com/harness/drone/pull/3107) ([tphoney](https://github.com/tphoney))
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## [2.0.4]
### Fixed
- DRON-97 remove use of request animation frame to prevent high CPU on tab refocus events.
## [2.0.3]
### Fixed
- DONE-91 handle extra slashes in url. [#3009](https://github.com/drone/drone/pull/3099).
## [2.0.2]
### Added
- Merge remote-tracking branch 'origin/master'
- prevent repository list short circuit in UI
- remove deprecated steps from building file [#3097](https://github.com/drone/drone/pull/3097)
- adding depends_on, image and detached fields to step [#3072](https://github.com/drone/drone/pull/3072)
- Add ctx.build.debug boolean [#3082](https://github.com/drone/drone/pull/3082)
- Bump github.com/google/go-jsonnet to v0.17.0 [#3084](https://github.com/drone/drone/pull/3084)
- bump go-scm v1.15.1 [#3096](https://github.com/drone/drone/pull/3096)
- bitbucket server build issue [#3092](https://github.com/drone/drone/pull/3092)
- update scm version [#3091](https://github.com/drone/drone/pull/3091)
- Limit graceful shutdown duration [#3093](https://github.com/drone/drone/pull/3093)
- bump user interface
- bump ui version
- ignore skip directive for promote and rollback events
- new feature: maximum open DB connections is configurable[#3089](https://github.com/drone/drone/pull/3089)
- jsonnet additional parameters [#3087](https://github.com/drone/drone/pull/3087)
- hide login button if user already authenticated
- new feature: configuration templates [#3081](https://github.com/drone/drone/pull/3081)
### Fixed
- various typos [#3088](https://github.com/drone/drone/pull/3088)
- handle error properly if template doesn't exist [#3095](https://github.com/drone/drone/pull/3093)
- oss build issue [#3086](https://github.com/drone/drone/pull/3086)
- graceful shutdown [#3083](https://github.com/drone/drone/pull/3083)
## [2.0.1]
### Added
- support for configuring the internal yaml cache size.
## [2.0.0]
### Added
- feature flags for mixed-mode database encryption.
### Changed
- user-interface re-design
### Breaking
- removed deprecated kubernetes integration in favor of official kubernetes runner.
- removed deprecated nomad integration in favor of official nomad runner.
## [1.10.1]
### Added
- support for repository-level concurrency limits.
- support for gitlab and github internal visibility on initial sync.
### Fixed
- create machine user with a custom API token.
## [1.10.0]
### Added
- support for starlark scripts in core.
- support for executing pipelines in debug mode.
## [1.9.2]
### Added
- update go-scm dependency to fix
## [1.9.1]
### Added
- support for increasing the http request timeout for extensions. [#2998](https://github.com/drone/drone/pull/2998).
- support for skipping a pipeline if the validation extension returns an ErrSkip.
- support for blocking a pipeline if the validation extension returns an ErrBlock.
### Fixed
- rollback endpoint should be available to users with write permission.
- retrying a build should re-use custom build parameters from parent build.
## [1.9.0] - 2020-07-12
### Added
- ui support for deployment list and summary.
- ui support for promoting and rolling back builds.
- feature flag to use static secret when signing webhooks, from @chiraggadasc.
### Fixed
- ui branch list improperly capped.
### Changed
- upgrade drone/envsubst dependency
- upgrade drone/go-scm dependency
## [1.8.1] - 2020-06-23
### Fixed
- support for gitea api pagination, repository sync hanging.
## [1.8.0] - 2020-06-10
### Added
- re-assigned repository ownership when deactivating a user.
- re-assigned repository ownership when deleting a user.
- de-activate a repository when deleting a user if re-assignment fails.
- de-activate a repository when deactivating a user if re-assignment fails.
- routine to cleanup builds stuck in a pending state.
- routine to cleanup builds stuck in a running state.
- private mode setting requires authentication to view public repositories.
### Fixed
- canceling a build emits a sql.ErrNoRows error.
- custom token is ignored when creating a user account via the API.
- machine accounts with sufficient permissions can create builds via the API.
### Changed
- upgraded Go toolchain to version 1.14.4.
## [1.7.0] - 2020-03-27
### Added
- endpoint to display the latest build by branch. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to display the latest build by pull request. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to display the latest build by environment. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete a branch from the index. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete a pull request from the index. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete an environment from the index. [#2940](https://github.com/drone/drone/pull/2940).
- page to view the latest build per branch.
### Fixed
- sync routine not executing asynchronously, being cancelled by http context.
- sync routine should ignore gitlab subrepositories
- convert deploy events in 0.8 yaml to promote events.
- do not execute cron job for disabled repositories. [#2931](https://github.com/drone/drone/issues/2931).
- remove trailing slash from gitea url to prevent oauth2 token refresh errors, by [@cmj0121](https://github.com/cmj0121). [#2920](https://github.com/drone/drone/issues/2920).
- disable font ligatures in build log output. [drone/drone-ui#322](https://github.com/drone/drone-ui/pull/322).
- missing am/pm in timestamps
## [1.6.5] - 2020-01-29
### Changed
- update version of go-scm
- update alpine version in docker images
- use ticker for cron jobs for more accurate timing
## [1.6.4] - 2019-12-30
### Added
- optionally enable pprof endpoints for profiling, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.3] - 2019-12-10
### Fixed
- disable caching generated yaml files by commit sha, by [@bradrydzewski](https://github.com/bradrydzewski).
### Added
- support for bitbucket skipverify, by [@toni-moreno](https://github.com/toni-moreno).
- support for gitea skipverify, by [@toni-moreno](https://github.com/toni-moreno).
## [1.6.2] - 2019-11-08
### Added
- support for loading license contents from env, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- regression not converting legacy pipeline when using new runners, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.1] - 2019-10-17
### Added
- updated autocert library in support of acme v2 protocol, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- fixed nil pointer when manually adding user from api, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.0] - 2019-10-04
### Added
- added nsswitch to docker images
- option to auto-cancel pending builds when newer build enqueued, by [@bradrydzewski](https://github.com/bradrydzewski). [#1980](https://github.com/drone/drone/issues/1980).
- endpoint to list all repositories in the database, by [@bradrydzewski](https://github.com/bradrydzewski). [#2785](https://github.com/drone/drone/issues/2785).
### Fixed
- improve sync to handle duplicate repository names with different unique identifiers, by [@bradrydzewski](https://github.com/bradrydzewski). [#2658](https://github.com/drone/drone/issues/2658). _You can revert to the previous sync logic with DRONE_DATABASE_LEGACY_BATCH=true_.
## [1.5.1] - 2019-09-30
### Added
- allow organization admins access to organization secret endpoints, by [@bradrydzewski](https://github.com/bradrydzewski). [#2838](https://github.com/drone/drone/issues/2838).
### Fixed
- fix invalid deep links in UI for github enterprise, by [@bradrydzewski](https://github.com/bradrydzewski).
- ensure correct casing when manually adding user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2766](https://github.com/drone/drone/issues/2766).
## [1.5.0] - 2019-09-28
### Added
- endpoint to execute a cron pipeline on-demand, by [@bradrydzewski](https://github.com/bradrydzewski). [#2781](https://github.com/drone/drone/issues/2781).
- endpoint to list builds by branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#1495](https://github.com/drone/drone/issues/1495).
- ignore skip comments when cron event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2835](https://github.com/drone/drone/issues/2835).
- support for admission extensions, by [@bradrydzewski](https://github.com/bradrydzewski). [#2043](https://github.com/drone/drone/issues/2043).
- endpoint to provide link to git resources, by [@bradrydzewski](https://github.com/bradrydzewski). [#2843](https://github.com/drone/drone/issues/2843).
- improve bitbucket status display text on new pull request screen, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- missing cron job name in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
- log lines not properly wrapping in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
[#309](https://github.com/drone/drone-ui/issues/309).
### Breaking
- the server now runs in multi-machine mode by default. In order to run the server in single-machine mode (agents disabled) you must set DRONE_AGENTS_DISABLED=true.
## [1.4.0] - 2019-09-12
### Added
- upgrade to Go 1.13 to resolve arm segfault, by [@KN4CK3R](https://github.com/KN4CK3R). [#2823](https://github.com/drone/drone/issues/2823).
- configure default visibility, by [@JordanSussman](https://github.com/JordanSussman). [#2824](https://github.com/drone/drone/issues/2824).
- configure default trusted flag, by [@vyckou](https://github.com/vyckou).
- support for validation plugins, by [@bradrydzewski](https://github.com/bradrydzewski). [#2266](https://github.com/drone/drone/issues/2266).
- support for conversion plugins, by [@bradrydzewski](https://github.com/bradrydzewski).
- support for cron event type, by [@bradrydzewski](https://github.com/bradrydzewski). [#2705](https://github.com/drone/drone/issues/2705).
- support for rollback event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2695](https://github.com/drone/drone/issues/2695).
- support for lets encrypt email, by [@bradrydzewski](https://github.com/bradrydzewski). [#2505](https://github.com/drone/drone/issues/2505).
### Removed
- Support for basic auth as an option for Gitea, by [@techknowlogick](https://giteahub.com/techknowlogick). [#2721](https://github.com/drone/drone/issues/2721)
### Fixed
- copy cron job name when restarting a cron job, by [@bradrydzewski](https://github.com/bradrydzewski). [#2760](https://github.com/drone/drone/issues/2760).
## [1.3.1] - 2019-08-26
### Added
- support for the GitHub deployment status API, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.3.0] - 2019-08-20
### Added
- support for storing logs in Azure Cloud Storage, by [@Lucretius](https://github.com/Lucretius). [#2788](https://github.com/drone/drone/pull/2788)
- support for windows server 1903, by [@bradrydzewski](https://github.com/bradrydzewski).
- button to view the full log file, by [@dramich](https://github.com/dramich). [drone/drone-ui#287](https://github.com/drone/drone-ui/pull/287).
### Fixed
- read gogs sha from webhook, by [@marcotuna](https://github.com/marcotuna).
- create bind volume on host if not exists, by [@bradrydzewski](https://github.com/bradrydzewski). [#2725](https://github.com/drone/drone/issues/2725).
- preserve whitespace in build logs, by [@geek1011](https://github.com/geek1011). [drone/drone-ui#294](https://github.com/drone/drone-ui/pull/294).
- enable log file download on firefox, by [@bobmanary](https://github.com/bobmanary). [drone/drone-ui#303](https://github.com/drone/drone-ui/pull/303)
### Security
- upgraded to Go 1.12.9 due to CVE-2019-9512 and CVE-2019-9514
## [1.2.3] - 2019-07-30
### Added
- disable github status for cron jobs
- support for action in conditionals, by [@bradrydzewski](https://github.com/bradrydzewski). [#2685](https://github.com/drone/drone/issues/2685).
### Fixed
- improve cancel logic for dangling stages, by [@bradrydzewski](https://github.com/bradrydzewski).
- improve error when kubernetes malforms the port configuration, by [@bradrydzewski](https://github.com/bradrydzewski). [#2742](https://github.com/drone/drone/issues/2742).
- copy parameters from parent build when promoting, by [@bradrydzewski](https://github.com/bradrydzewski). [#2748](https://github.com/drone/drone/issues/2748).
## [1.2.2] - 2019-07-29
### Added
- support for legacy environment variables
- support for legacy workspace based on repository name
- support for github deployment hooks
- provide base sha for github pull requests
- option to filter webhooks by event and type
- upgrade drone-yaml to v1.2.2
- upgrade drone-runtime to v1.0.7
### Fixed
- error when manually creating an empty user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2738](https://github.com/drone/drone/issues/2738).
## [1.2.1] - 2019-06-11
### Added
- support for legacy tokens to ease upgrade path, by [@bradrydzewski](https://github.com/bradrydzewski). [#2713](https://github.com/drone/drone/issues/2713).
- include repository name and id in batch update error message, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- fix inconsistent base64 encoding and decoding of encrypted secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-yaml to version 1.1.2 for improved 0.8 to 1.0 yaml marshal escaping.
- update drone-yaml to version 1.1.3 for improved 0.8 to 1.0 workspace conversion.
## [1.2.0] - 2019-05-30
### Added
- endpoint to trigger new build for default branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- endpoint to trigger new build for branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- endpoint to trigger new build for branch and sha, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- enable optional prometheus metrics guest access, by [@janberktold](https://github.com/janberktold)
- fallback to database when logs not found in s3, by [@bradrydzewski](https://github.com/bradrydzewski). [#2689](https://github.com/drone/drone/issues/2689).
- support for custom stage definitions and runners, by [@bradrydzewski](https://github.com/bradrydzewski). [#2680](https://github.com/drone/drone/issues/2680).
- update drone-yaml to version 1.1.0
### Fixed
- retrieve latest build by branch, by [@tboerger](https://github.com/tboerger).
- copy the fork value when restarting a build, by [@bradrydzewski](https://github.com/bradrydzewski). [#2708](https://github.com/drone/drone/issues/2708).
- make healthz available without redirect, by [@bradrydzewski](https://github.com/bradrydzewski). [#2706](https://github.com/drone/drone/issues/2706).
## [1.1.0] - 2019-04-23
### Added
- specify a user for the pipeline step, by [@bradrydzewski](https://github.com/bradrydzewski). [#2651](https://github.com/drone/drone/issues/2651).
- support for Gitea oauth2, by [@techknowlogick](https://github.com/techknowlogick). [#2622](https://github.com/drone/drone/pull/2622).
- ping the docker daemon before starting the agent, by [@bradrydzewski](https://github.com/bradrydzewski). [#2495](https://github.com/drone/drone/issues/2495).
- support for Cron job name in Yaml trigger block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
- support for Cron job name in Yaml when block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
- sqlite username column changed to case-insensitive, by [@bradrydzewski](https://github.com/bradrydzewski).
- endpoint to purge repository from database, by [@bradrydzewski](https://github.com/bradrydzewski).
- support for per-organization secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
- include system metadata in global webhooks, by [@bradrydzewski](https://github.com/bradrydzewski).
- ability to customize cookie secure flag, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-yaml from version 1.0.6 to 1.0.8.
- update drone-runtime from version 1.0.4 to 1.0.6.
- update go-scm from version 1.0.3 to 1.0.4.
### Fixed
- fixed error in mysql table creation syntax, from [@xuyang2](https://github.com/xuyang2). [#2677](https://github.com/drone/drone/pull/2677).
- fixed stuck builds when upstream dependency is skipped, from [@bradrydzewski](https://github.com/bradrydzewski). [#2634](https://github.com/drone/drone/issues/2634).
- fixed issue running steps with dependencies on failure, from [@bradrydzewski](https://github.com/bradrydzewski). [#2667](https://github.com/drone/drone/issues/2667).
## [1.0.1] - 2019-04-10
### Added
- pass stage environment variables to pipeline steps, by [@bradrydzewski](https://github.com/bradrydzewski).
- update go-scm to version 1.3.0, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-runtime to version to 1.0.4, by [@bradrydzewski](https://github.com/bradrydzewski).
- ping docker daemon before agent starts to ensure connectivity, by [@bradrydzewski](https://github.com/bradrydzewski).
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*

90
Dockerfile Normal file
View File

@ -0,0 +1,90 @@
# ---------------------------------------------------------#
# Build web image #
# ---------------------------------------------------------#
FROM node:16 as web
WORKDIR /usr/src/app
COPY web/package.json ./
COPY web/yarn.lock ./
ARG GITHUB_ACCESS_TOKEN
# If you are building your code for production
# RUN npm ci --omit=dev
COPY ./web .
RUN yarn && yarn build && yarn cache clean
# ---------------------------------------------------------#
# Build gitness image #
# ---------------------------------------------------------#
FROM golang:1.19-alpine as builder
RUN apk update \
&& apk add --no-cache protoc build-base git
# Setup workig dir
WORKDIR /app
# Access to private repos
ARG GITHUB_ACCESS_TOKEN
RUN git config --global url."https://${GITHUB_ACCESS_TOKEN}:x-oauth-basic@github.com/harness".insteadOf "https://github.com/harness"
RUN git config --global --add safe.directory '/app'
RUN go env -w GOPRIVATE=github.com/harness/*
# Get dependancies - will also be cached if we won't change mod/sum
COPY go.mod .
COPY go.sum .
COPY Makefile .
RUN make dep
RUN make tools
# COPY the source code as the last step
COPY . .
COPY --from=web /usr/src/app/dist /app/web/dist
# build
ARG GIT_COMMIT
ARG GITNESS_VERSION_MAJOR
ARG GITNESS_VERSION_MINOR
ARG GITNESS_VERSION_PATCH
ARG BUILD_TAGS
# set required build flags
RUN CGO_ENABLED=1 \
GOOS=linux \
GOARCH=amd64 \
BUILD_TAGS=${BUILD_TAGS} \
make build
### Pull CA Certs
FROM alpine:latest as cert-image
RUN apk --update add ca-certificates
# ---------------------------------------------------------#
# Create final image #
# ---------------------------------------------------------#
FROM alpine/git:2.36.3 as final
# setup app dir and its content
WORKDIR /app
VOLUME /data
ENV XDG_CACHE_HOME /data
ENV GITRPC_SERVER_GIT_ROOT /data
ENV GITNESS_DATABASE_DRIVER sqlite3
ENV GITNESS_DATABASE_DATASOURCE /data/database.sqlite
ENV GITNESS_METRIC_ENABLED=true
ENV GITNESS_METRIC_ENDPOINT=https://stats.drone.ci/api/v1/gitness
ENV GITNESS_TOKEN_COOKIE_NAME=token
COPY --from=builder /app/gitness /app/gitness
COPY --from=cert-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
EXPOSE 3000
EXPOSE 3001
ENTRYPOINT [ "/app/gitness", "server" ]

View File

@ -1,326 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## [2.0.4]
### Fixed
- DRON-97 remove use of request animation frame to prevent high CPU on tab refocus events.
## [2.0.3]
### Fixed
- DONE-91 handle extra slashes in url. [#3009](https://github.com/drone/drone/pull/3099).
## [2.0.2]
### Added
- Merge remote-tracking branch 'origin/master'
- prevent repository list short circuit in UI
- remove deprecated steps from building file [#3097](https://github.com/drone/drone/pull/3097)
- adding depends_on, image and detached fields to step [#3072](https://github.com/drone/drone/pull/3072)
- Add ctx.build.debug boolean [#3082](https://github.com/drone/drone/pull/3082)
- Bump github.com/google/go-jsonnet to v0.17.0 [#3084](https://github.com/drone/drone/pull/3084)
- bump go-scm v1.15.1 [#3096](https://github.com/drone/drone/pull/3096)
- bitbucket server build issue [#3092](https://github.com/drone/drone/pull/3092)
- update scm version [#3091](https://github.com/drone/drone/pull/3091)
- Limit graceful shutdown duration [#3093](https://github.com/drone/drone/pull/3093)
- bump user interface
- bump ui version
- ignore skip directive for promote and rollback events
- new feature: maximum open DB connections is configurable[#3089](https://github.com/drone/drone/pull/3089)
- jsonnet additional parameters [#3087](https://github.com/drone/drone/pull/3087)
- hide login button if user already authenticated
- new feature: configuration templates [#3081](https://github.com/drone/drone/pull/3081)
### Fixed
- various typos [#3088](https://github.com/drone/drone/pull/3088)
- handle error properly if template doesn't exist [#3095](https://github.com/drone/drone/pull/3093)
- oss build issue [#3086](https://github.com/drone/drone/pull/3086)
- graceful shutdown [#3083](https://github.com/drone/drone/pull/3083)
## [2.0.1]
### Added
- support for configuring the internal yaml cache size.
## [2.0.0]
### Added
- feature flags for mixed-mode database encryption.
### Changed
- user-interface re-design
### Breaking
- removed deprecated kubernetes integration in favor of official kubernetes runner.
- removed deprecated nomad integration in favor of official nomad runner.
## [1.10.1]
### Added
- support for repository-level concurrency limits.
- support for gitlab and github internal visibility on initial sync.
### Fixed
- create machine user with a custom API token.
## [1.10.0]
### Added
- support for starlark scripts in core.
- support for executing pipelines in debug mode.
## [1.9.2]
### Added
- update go-scm dependency to fix
## [1.9.1]
### Added
- support for increasing the http request timeout for extensions. [#2998](https://github.com/drone/drone/pull/2998).
- support for skipping a pipeline if the validation extension returns an ErrSkip.
- support for blocking a pipeline if the validation extension returns an ErrBlock.
### Fixed
- rollback endpoint should be available to users with write permission.
- retrying a build should re-use custom build parameters from parent build.
## [1.9.0] - 2020-07-12
### Added
- ui support for deployment list and summary.
- ui support for promoting and rolling back builds.
- feature flag to use static secret when signing webhooks, from @chiraggadasc.
### Fixed
- ui branch list improperly capped.
### Changed
- upgrade drone/envsubst dependency
- upgrade drone/go-scm dependency
## [1.8.1] - 2020-06-23
### Fixed
- support for gitea api pagination, repository sync hanging.
## [1.8.0] - 2020-06-10
### Added
- re-assigned repository ownership when deactivating a user.
- re-assigned repository ownership when deleting a user.
- de-activate a repository when deleting a user if re-assignment fails.
- de-activate a repository when deactivating a user if re-assignment fails.
- routine to cleanup builds stuck in a pending state.
- routine to cleanup builds stuck in a running state.
- private mode setting requires authentication to view public repositories.
### Fixed
- canceling a build emits a sql.ErrNoRows error.
- custom token is ignored when creating a user account via the API.
- machine accounts with sufficient permissions can create builds via the API.
### Changed
- upgraded Go toolchain to version 1.14.4.
## [1.7.0] - 2020-03-27
### Added
- endpoint to display the latest build by branch. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to display the latest build by pull request. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to display the latest build by environment. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete a branch from the index. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete a pull request from the index. [#2940](https://github.com/drone/drone/pull/2940).
- endpoint to delete an environment from the index. [#2940](https://github.com/drone/drone/pull/2940).
- page to view the latest build per branch.
### Fixed
- sync routine not executing asynchronously, being cancelled by http context.
- sync routine should ignore gitlab subrepositories
- convert deploy events in 0.8 yaml to promote events.
- do not execute cron job for disabled repositories. [#2931](https://github.com/drone/drone/issues/2931).
- remove trailing slash from gitea url to prevent oauth2 token refresh errors, by [@cmj0121](https://github.com/cmj0121). [#2920](https://github.com/drone/drone/issues/2920).
- disable font ligatures in build log output. [drone/drone-ui#322](https://github.com/drone/drone-ui/pull/322).
- missing am/pm in timestamps
## [1.6.5] - 2020-01-29
### Changed
- update version of go-scm
- update alpine version in docker images
- use ticker for cron jobs for more accurate timing
## [1.6.4] - 2019-12-30
### Added
- optionally enable pprof endpoints for profiling, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.3] - 2019-12-10
### Fixed
- disable caching generated yaml files by commit sha, by [@bradrydzewski](https://github.com/bradrydzewski).
### Added
- support for bitbucket skipverify, by [@toni-moreno](https://github.com/toni-moreno).
- support for gitea skipverify, by [@toni-moreno](https://github.com/toni-moreno).
## [1.6.2] - 2019-11-08
### Added
- support for loading license contents from env, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- regression not converting legacy pipeline when using new runners, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.1] - 2019-10-17
### Added
- updated autocert library in support of acme v2 protocol, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- fixed nil pointer when manually adding user from api, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.6.0] - 2019-10-04
### Added
- added nsswitch to docker images
- option to auto-cancel pending builds when newer build enqueued, by [@bradrydzewski](https://github.com/bradrydzewski). [#1980](https://github.com/drone/drone/issues/1980).
- endpoint to list all repositories in the database, by [@bradrydzewski](https://github.com/bradrydzewski). [#2785](https://github.com/drone/drone/issues/2785).
### Fixed
- improve sync to handle duplicate repository names with different unique identifiers, by [@bradrydzewski](https://github.com/bradrydzewski). [#2658](https://github.com/drone/drone/issues/2658). _You can revert to the previous sync logic with DRONE_DATABASE_LEGACY_BATCH=true_.
## [1.5.1] - 2019-09-30
### Added
- allow organization admins access to organization secret endpoints, by [@bradrydzewski](https://github.com/bradrydzewski). [#2838](https://github.com/drone/drone/issues/2838).
### Fixed
- fix invalid deep links in UI for github enterprise, by [@bradrydzewski](https://github.com/bradrydzewski).
- ensure correct casing when manually adding user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2766](https://github.com/drone/drone/issues/2766).
## [1.5.0] - 2019-09-28
### Added
- endpoint to execute a cron pipeline on-demand, by [@bradrydzewski](https://github.com/bradrydzewski). [#2781](https://github.com/drone/drone/issues/2781).
- endpoint to list builds by branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#1495](https://github.com/drone/drone/issues/1495).
- ignore skip comments when cron event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2835](https://github.com/drone/drone/issues/2835).
- support for admission extensions, by [@bradrydzewski](https://github.com/bradrydzewski). [#2043](https://github.com/drone/drone/issues/2043).
- endpoint to provide link to git resources, by [@bradrydzewski](https://github.com/bradrydzewski). [#2843](https://github.com/drone/drone/issues/2843).
- improve bitbucket status display text on new pull request screen, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- missing cron job name in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
- log lines not properly wrapping in user interface, by [@bradrydzewski](https://github.com/bradrydzewski).
[#309](https://github.com/drone/drone-ui/issues/309).
### Breaking
- the server now runs in multi-machine mode by default. In order to run the server in single-machine mode (agents disabled) you must set DRONE_AGENTS_DISABLED=true.
## [1.4.0] - 2019-09-12
### Added
- upgrade to Go 1.13 to resolve arm segfault, by [@KN4CK3R](https://github.com/KN4CK3R). [#2823](https://github.com/drone/drone/issues/2823).
- configure default visibility, by [@JordanSussman](https://github.com/JordanSussman). [#2824](https://github.com/drone/drone/issues/2824).
- configure default trusted flag, by [@vyckou](https://github.com/vyckou).
- support for validation plugins, by [@bradrydzewski](https://github.com/bradrydzewski). [#2266](https://github.com/drone/drone/issues/2266).
- support for conversion plugins, by [@bradrydzewski](https://github.com/bradrydzewski).
- support for cron event type, by [@bradrydzewski](https://github.com/bradrydzewski). [#2705](https://github.com/drone/drone/issues/2705).
- support for rollback event, by [@bradrydzewski](https://github.com/bradrydzewski). [#2695](https://github.com/drone/drone/issues/2695).
- support for lets encrypt email, by [@bradrydzewski](https://github.com/bradrydzewski). [#2505](https://github.com/drone/drone/issues/2505).
### Removed
- Support for basic auth as an option for Gitea, by [@techknowlogick](https://giteahub.com/techknowlogick). [#2721](https://github.com/drone/drone/issues/2721)
### Fixed
- copy cron job name when restarting a cron job, by [@bradrydzewski](https://github.com/bradrydzewski). [#2760](https://github.com/drone/drone/issues/2760).
## [1.3.1] - 2019-08-26
### Added
- support for the GitHub deployment status API, by [@bradrydzewski](https://github.com/bradrydzewski).
## [1.3.0] - 2019-08-20
### Added
- support for storing logs in Azure Cloud Storage, by [@Lucretius](https://github.com/Lucretius). [#2788](https://github.com/drone/drone/pull/2788)
- support for windows server 1903, by [@bradrydzewski](https://github.com/bradrydzewski).
- button to view the full log file, by [@dramich](https://github.com/dramich). [drone/drone-ui#287](https://github.com/drone/drone-ui/pull/287).
### Fixed
- read gogs sha from webhook, by [@marcotuna](https://github.com/marcotuna).
- create bind volume on host if not exists, by [@bradrydzewski](https://github.com/bradrydzewski). [#2725](https://github.com/drone/drone/issues/2725).
- preserve whitespace in build logs, by [@geek1011](https://github.com/geek1011). [drone/drone-ui#294](https://github.com/drone/drone-ui/pull/294).
- enable log file download on firefox, by [@bobmanary](https://github.com/bobmanary). [drone/drone-ui#303](https://github.com/drone/drone-ui/pull/303)
### Security
- upgraded to Go 1.12.9 due to CVE-2019-9512 and CVE-2019-9514
## [1.2.3] - 2019-07-30
### Added
- disable github status for cron jobs
- support for action in conditionals, by [@bradrydzewski](https://github.com/bradrydzewski). [#2685](https://github.com/drone/drone/issues/2685).
### Fixed
- improve cancel logic for dangling stages, by [@bradrydzewski](https://github.com/bradrydzewski).
- improve error when kubernetes malforms the port configuration, by [@bradrydzewski](https://github.com/bradrydzewski). [#2742](https://github.com/drone/drone/issues/2742).
- copy parameters from parent build when promoting, by [@bradrydzewski](https://github.com/bradrydzewski). [#2748](https://github.com/drone/drone/issues/2748).
## [1.2.2] - 2019-07-29
### Added
- support for legacy environment variables
- support for legacy workspace based on repository name
- support for github deployment hooks
- provide base sha for github pull requests
- option to filter webhooks by event and type
- upgrade drone-yaml to v1.2.2
- upgrade drone-runtime to v1.0.7
### Fixed
- error when manually creating an empty user, by [@bradrydzewski](https://github.com/bradrydzewski). [#2738](https://github.com/drone/drone/issues/2738).
## [1.2.1] - 2019-06-11
### Added
- support for legacy tokens to ease upgrade path, by [@bradrydzewski](https://github.com/bradrydzewski). [#2713](https://github.com/drone/drone/issues/2713).
- include repository name and id in batch update error message, by [@bradrydzewski](https://github.com/bradrydzewski).
### Fixed
- fix inconsistent base64 encoding and decoding of encrypted secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-yaml to version 1.1.2 for improved 0.8 to 1.0 yaml marshal escaping.
- update drone-yaml to version 1.1.3 for improved 0.8 to 1.0 workspace conversion.
## [1.2.0] - 2019-05-30
### Added
- endpoint to trigger new build for default branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- endpoint to trigger new build for branch, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- endpoint to trigger new build for branch and sha, by [@bradrydzewski](https://github.com/bradrydzewski). [#2679](https://github.com/drone/drone/issues/2679).
- enable optional prometheus metrics guest access, by [@janberktold](https://github.com/janberktold)
- fallback to database when logs not found in s3, by [@bradrydzewski](https://github.com/bradrydzewski). [#2689](https://github.com/drone/drone/issues/2689).
- support for custom stage definitions and runners, by [@bradrydzewski](https://github.com/bradrydzewski). [#2680](https://github.com/drone/drone/issues/2680).
- update drone-yaml to version 1.1.0
### Fixed
- retrieve latest build by branch, by [@tboerger](https://github.com/tboerger).
- copy the fork value when restarting a build, by [@bradrydzewski](https://github.com/bradrydzewski). [#2708](https://github.com/drone/drone/issues/2708).
- make healthz available without redirect, by [@bradrydzewski](https://github.com/bradrydzewski). [#2706](https://github.com/drone/drone/issues/2706).
## [1.1.0] - 2019-04-23
### Added
- specify a user for the pipeline step, by [@bradrydzewski](https://github.com/bradrydzewski). [#2651](https://github.com/drone/drone/issues/2651).
- support for Gitea oauth2, by [@techknowlogick](https://github.com/techknowlogick). [#2622](https://github.com/drone/drone/pull/2622).
- ping the docker daemon before starting the agent, by [@bradrydzewski](https://github.com/bradrydzewski). [#2495](https://github.com/drone/drone/issues/2495).
- support for Cron job name in Yaml trigger block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
- support for Cron job name in Yaml when block, by [@bradrydzewski](https://github.com/bradrydzewski). [#2628](https://github.com/drone/drone/issues/2628).
- sqlite username column changed to case-insensitive, by [@bradrydzewski](https://github.com/bradrydzewski).
- endpoint to purge repository from database, by [@bradrydzewski](https://github.com/bradrydzewski).
- support for per-organization secrets, by [@bradrydzewski](https://github.com/bradrydzewski).
- include system metadata in global webhooks, by [@bradrydzewski](https://github.com/bradrydzewski).
- ability to customize cookie secure flag, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-yaml from version 1.0.6 to 1.0.8.
- update drone-runtime from version 1.0.4 to 1.0.6.
- update go-scm from version 1.0.3 to 1.0.4.
### Fixed
- fixed error in mysql table creation syntax, from [@xuyang2](https://github.com/xuyang2). [#2677](https://github.com/drone/drone/pull/2677).
- fixed stuck builds when upstream dependency is skipped, from [@bradrydzewski](https://github.com/bradrydzewski). [#2634](https://github.com/drone/drone/issues/2634).
- fixed issue running steps with dependencies on failure, from [@bradrydzewski](https://github.com/bradrydzewski). [#2667](https://github.com/drone/drone/issues/2667).
## [1.0.1] - 2019-04-10
### Added
- pass stage environment variables to pipeline steps, by [@bradrydzewski](https://github.com/bradrydzewski).
- update go-scm to version 1.3.0, by [@bradrydzewski](https://github.com/bradrydzewski).
- update drone-runtime to version to 1.0.4, by [@bradrydzewski](https://github.com/bradrydzewski).
- ping docker daemon before agent starts to ensure connectivity, by [@bradrydzewski](https://github.com/bradrydzewski).

89
LICENSE
View File

@ -1,89 +0,0 @@
Copyright 2019 Drone.IO, Inc.
The Drone Community Edition is licensed under the Apache License,
Version 2.0 (the "Apache License"). You may obtain a copy of the
Apache License at
http://www.apache.org/licenses/LICENSE-2.0
The Drone Enterprise Edition is licensed under the Drone
Non-Commercial License (the "Non-Commercial License"). A copy of
the Non-Commercial License is provided below.
The source files in this repository have a header indicating
which license they are under. The BUILDING_OSS file provides
instructions for creating the Community Edition distribution
subject to the terms of the Apache License.
-----------------------------------------------------------------
Drone Non-Commercial License
Contributor: Drone.IO, Inc.
Source Code: https://github.com/harness/drone
This license lets you use and share this software for free,
with a trial-length time limit on commercial use. Specifically:
If you follow the rules below, you may do everything with this
software that would otherwise infringe either the contributor's
copyright in it, any patent claim the contributor can license
that covers this software as of the contributor's latest
contribution, or both.
1. You must limit use of this software in any manner primarily
intended for or directed toward commercial advantage or
private monetary compensation to a trial period of 32
consecutive calendar days. This limit does not apply to use in
developing feedback, modifications, or extensions that you
contribute back to those giving this license.
2. Ensure everyone who gets a copy of this software from you, in
source code or any other form, gets the text of this license
and the contributor and source code lines above.
3. Do not make any legal claim against anyone for infringing any
patent claim they would infringe by using this software alone,
accusing this software, with or without changes, alone or as
part of a larger application.
You are excused for unknowingly breaking rule 1 if you stop
doing anything requiring this license within 30 days of
learning you broke the rule.
**This software comes as is, without any warranty at all. As far
as the law allows, the contributor will not be liable for any
damages related to this software or this license, for any kind of
legal claim.**
-----------------------------------------------------------------
Waiver: Individual and Small Business
Contributor waives the terms of rule 1 for companies meeting all
the following criteria, counting all subsidiaries and affiliated
entities as one:
1. worldwide annual gross revenue under $5 million US dollars,
per generally accepted accounting principles
2. less than $5 million US dollars in all-time aggregate debt and
equity financing
Contributor will not revoke this waiver, but may change terms for
future versions of the software.
-----------------------------------------------------------------
Waiver: Low Usage
Contributor waives the terms of rule 1 for companies meeting all
the following criteria, counting all subsidiaries and affiliated
entities as one:
1. less than 5,000 total pipelines executed using this software
in the immediately preceding, year-long period
Contributor will not revoke this waiver, but may change terms for
future versions of the software.

201
LICENSE.md Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

163
Makefile Normal file
View File

@ -0,0 +1,163 @@
ifndef GOPATH
GOPATH := $(shell go env GOPATH)
endif
ifndef GOBIN # derive value from gopath (default to first entry, similar to 'go get')
GOBIN := $(shell go env GOPATH | sed 's/:.*//')/bin
endif
ifndef DOCKER_BUILD_OPTS
DOCKER_BUILD_OPTS :=
endif
tools = $(addprefix $(GOBIN)/, golangci-lint goimports govulncheck protoc-gen-go protoc-gen-go-grpc gci)
deps = $(addprefix $(GOBIN)/, wire dbmate)
LDFLAGS = "-X github.com/harness/gitness/version.GitCommit=${GIT_COMMIT} -X github.com/harness/gitness/version.major=${GITNESS_VERSION_MAJOR} -X github.com/harness/gitness/version.minor=${GITNESS_VERSION_MINOR} -X github.com/harness/gitness/version.patch=${GITNESS_VERSION_PATCH}"
ifneq (,$(wildcard ./.local.env))
include ./.local.env
export
endif
.DEFAULT_GOAL := all
ifeq ($(BUILD_TAGS),)
BUILD_TAGS := sqlite
endif
BUILD_TAGS := $(BUILD_TAGS),gogit
###############################################################################
#
# Initialization
#
###############################################################################
dep: $(deps) ## Install the deps required to generate code and build gitness
@echo "Installing dependencies"
@go mod download
tools: $(tools) ## Install tools required for the build
@echo "Installed tools"
###############################################################################
#
# Build and testing rules
#
###############################################################################
build: generate ## Build the all-in-one gitness binary
@echo "Building Gitness Server"
go build -tags=${BUILD_TAGS} -ldflags=${LDFLAGS} -o ./gitness ./cmd/gitness
build-gitrpc: generate ## Build the gitrpc binary
@echo "Building GitRPC Server"
go build -tags=${BUILD_TAGS} -ldflags=${LDFLAGS} -o ./gitrpcserver ./cmd/gitrpcserver
build-githook: generate ## Build the githook binary for gitness
@echo "Building gitness GitHook Binary"
go build -tags=${BUILD_TAGS} -ldflags=${LDFLAGS} -o ./gitness-githook ./cmd/gitness-githook
test: generate ## Run the go tests
@echo "Running tests"
go test -v -coverprofile=coverage.out ./internal/...
go tool cover -html=coverage.out
run: dep ## Run the gitness binary from source
@go run -race -ldflags=${LDFLAGS} ./cmd/gitness
###############################################################################
#
# Code Formatting and linting
#
###############################################################################
format: tools # Format go code and error if any changes are made
@echo "Formating ..."
@goimports -w .
@gci write --custom-order -s standard -s "prefix(github.com/harness/gitness)" -s default -s blank -s dot .
@echo "Formatting complete"
sec:
@echo "Vulnerability detection $(1)"
@govulncheck ./...
lint: tools generate # lint the golang code
@echo "Linting $(1)"
@golangci-lint run --timeout=3m --verbose
###############################################################################
# Code Generation
#
# Some code generation can be slow, so we only run it if
# the source file has changed.
###############################################################################
generate: wire proto
@echo "Generating Code"
wire: cmd/gitness/wire_gen.go cmd/gitrpcserver/wire_gen.go
force-wire: ## Force wire code generation
@sh ./scripts/wire/server/standalone.sh
@sh ./scripts/wire/gitrpcserver/wire.sh
cmd/gitness/wire_gen.go: cmd/gitness/wire.go
@sh ./scripts/wire/server/standalone.sh
cmd/gitrpcserver/wire_gen.go: cmd/gitrpcserver/wire.go
@sh ./scripts/wire/gitrpcserver/wire.sh
proto: ## generate proto files for gitrpc integration
@protoc --proto_path=./gitrpc/proto \
--go_out=./gitrpc/rpc \
--go_opt=paths=source_relative \
--go-grpc_out=./gitrpc/rpc \
--go-grpc_opt=paths=source_relative \
./gitrpc/proto/*.proto
###############################################################################
# Install Tools and deps
#
# These targets specify the full path to where the tool is installed
# If the tool already exists it wont be re-installed.
###############################################################################
update-tools: delete-tools $(tools) ## Update the tools by deleting and re-installing
delete-tools: ## Delete the tools
@rm $(tools) || true
# Install golangci-lint
$(GOBIN)/golangci-lint:
@echo "🔘 Installing golangci-lint... (`date '+%H:%M:%S'`)"
@curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN)
# Install goimports to format code
$(GOBIN)/goimports:
@echo "🔘 Installing goimports ... (`date '+%H:%M:%S'`)"
@go install golang.org/x/tools/cmd/goimports
# Install wire to generate dependency injection
$(GOBIN)/wire:
go install github.com/google/wire/cmd/wire@latest
# Install dbmate to perform db migrations
$(GOBIN)/dbmate:
go install github.com/amacneil/dbmate@v1.15.0
$(GOBIN)/govulncheck:
go install golang.org/x/vuln/cmd/govulncheck@latest
$(GOBIN)/protoc-gen-go:
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$(GOBIN)/protoc-gen-go-grpc:
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
$(GOBIN)/gci:
go install github.com/daixiang0/gci@latest
help: ## show help message
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% 0-9a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
.PHONY: delete-tools update-tools help format lint

14
NOTICE
View File

@ -1,14 +0,0 @@
Drone
Copyright 2019 Drone.IO, Inc
This product includes software developed at Drone.IO, Inc.
(http://drone.io/).
This product includes software developed by Docker, Inc.
(https://www.docker.com/).
This product includes software developed by Canonical Ltd.
(https://www.canonical.com/).
This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

101
README.md Normal file
View File

@ -0,0 +1,101 @@
# Gitness
Your lightweight, super fast code hosting and continuous integration service (powered by Drone)
For more information, please visit [gitness.com](https://gitness.com/)
# Pre-Requisites
Install the latest stable version of Node and Go version 1.19 or higher, and then install the below Go programs. Ensure the GOPATH [bin directory](https://go.dev/doc/gopath_code#GOPATH) is added to your PATH.
Install protobuf
- Check if you've already installed protobuf ```protoc --version```
- If your version is different than v3.21.11, run ```brew unlink protobuf```
- Get v3.21.11 ```curl -s https://raw.githubusercontent.com/Homebrew/homebrew-core/9de8de7a533609ebfded833480c1f7c05a3448cb/Formula/protobuf.rb > /tmp/protobuf.rb```
- Install it ```brew install /tmp/protobuf.rb```
- Check out your version ```protoc --version```
Install protoc-gen-go and protoc-gen-go-rpc:
- Install protoc-gen-go v1.28.1 ```go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1```
(Note that this will install a binary in $GOBIN so make sure $GOBIN is in your $PATH)
- Install protoc-gen-go-grpc v1.2.0 ```go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0```
```bash
$ make dep
$ make tools
```
# Build
Build the user interface:
```bash
$ pushd web
$ yarn install
$ yarn build
$ popd
```
Build the server and command line tools:
```bash
$ make build
```
# Run
This project supports all operating systems and architectures supported by Go. This means you can build and run the system on your machine; docker containers are not required for local development and testing.
Start the server at `localhost:3000`
```bash
./gitness server .local.env
```
# User Interface
This project includes a full user interface for interacting with the system. When you run the application, you can access the user interface by navigating to `http://localhost:3000` in your browser.
# Swagger
This project includes a swagger specification. When you run the application, you can access the swagger specification by navigating to `http://localhost:3000/swagger` in your browser (for raw yaml see `http://localhost:3000/openapi.yaml`).
## Auto-Generate Gitness API Client used by UI using Swagger
Please make sure to update the autogenerated client code used by the UI when adding new rest APIs.
To regenerate the code, please execute the following steps:
- Run local gitness instance with latest changes
- Get latest OpenAPI specs from `http://localhost:3000/openapi.yaml` and store it in `web/src/services/code/swagger.yaml`
The latest API changes should now be reflected in `web/src/services/code/index.tsx`
# REST API
Please refer to the swagger for the specification of our rest API.
For testing, it's simplest to execute operations as the default user `admin` using a PAT:
```bash
# LOGIN (user: admin, pw: changeit)
$ ./gitness login
# GENERATE PAT (1 YEAR VALIDITY)
$ ./gitness user pat "my-pat-uid" 2592000
```
The command outputs a valid PAT that has been granted full access as the user.
The token can then be send as part of the `Authorization` header with Postman or curl:
```bash
$ curl http://localhost:3000/api/v1/user \
-H "Authorization: Bearer $TOKEN"
```
# CLI
This project includes VERY basic command line tools for development and running the service. Please remember that you must start the server before you can execute commands.
For a full list of supported operations, please see
```bash
$ ./gitness --help
```

View File

@ -1,129 +0,0 @@
# https://taskfile.org
version: '2'
tasks:
install:
dir: cmd/drone-server
cmds: [ go install -v ]
env:
GO111MODULE: on
build:
cmds:
- task: build-base
vars: { name: server }
build-base:
env:
GOOS: linux
GOARCH: amd64
CGO_ENABLED: '0'
GO111MODULE: 'on'
cmds:
- cmd: >
go build -o release/linux/amd64/drone-{{.name}}
github.com/drone/drone/cmd/drone-{{.name}}
cleanup:
cmds:
- rm -rf release
docker:
cmds:
- task: docker-base
vars: { name: server, image: drone/drone }
docker-base:
vars:
GIT_BRANCH:
sh: git rev-parse --abbrev-ref HEAD
cmds:
- cmd: docker rmi {{.image}}
ignore_error: true
- cmd: docker rmi {{.image}}:{{.GIT_BRANCH}}
ignore_error: true
- cmd: >
docker build --rm
-f docker/Dockerfile.{{.name}}.linux.amd64
-t {{.image}} .
- cmd: >
docker tag {{.image}} {{.image}}:{{.GIT_BRANCH}}
test:
cmds:
- go test ./...
env:
GO111MODULE: 'on'
test-mysql:
env:
DRONE_DATABASE_DRIVER: mysql
DRONE_DATABASE_DATASOURCE: root@tcp(localhost:3306)/test?parseTime=true
GO111MODULE: 'on'
cmds:
- cmd: docker kill mysql
silent: true
ignore_error: true
- cmd: >
docker run
-p 3306:3306
--env MYSQL_DATABASE=test
--env MYSQL_ALLOW_EMPTY_PASSWORD=yes
--name mysql
--detach
--rm
mysql:5.7
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
- cmd: go test -count=1 github.com/drone/drone/store/batch
- cmd: go test -count=1 github.com/drone/drone/store/batch2
- cmd: go test -count=1 github.com/drone/drone/store/build
- cmd: go test -count=1 github.com/drone/drone/store/card
- cmd: go test -count=1 github.com/drone/drone/store/cron
- cmd: go test -count=1 github.com/drone/drone/store/logs
- cmd: go test -count=1 github.com/drone/drone/store/perm
- cmd: go test -count=1 github.com/drone/drone/store/repos
- cmd: go test -count=1 github.com/drone/drone/store/secret
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
- cmd: go test -count=1 github.com/drone/drone/store/stage
- cmd: go test -count=1 github.com/drone/drone/store/step
- cmd: go test -count=1 github.com/drone/drone/store/template
- cmd: go test -count=1 github.com/drone/drone/store/user
- cmd: docker kill mysql
test-postgres:
env:
DRONE_DATABASE_DRIVER: postgres
DRONE_DATABASE_DATASOURCE: host=localhost user=postgres password=postgres dbname=postgres sslmode=disable
GO111MODULE: 'on'
cmds:
- cmd: docker kill postgres
ignore_error: true
silent: false
- silent: false
cmd: >
docker run
-p 5432:5432
--env POSTGRES_PASSWORD=postgres
--env POSTGRES_USER=postgres
--name postgres
--detach
--rm
postgres:9-alpine
- cmd: go test -count=1 github.com/drone/drone/store/batch
- cmd: go test -count=1 github.com/drone/drone/store/batch2
- cmd: go test -count=1 github.com/drone/drone/store/build
- cmd: go test -count=1 github.com/drone/drone/store/card
- cmd: go test -count=1 github.com/drone/drone/store/cron
- cmd: go test -count=1 github.com/drone/drone/store/logs
- cmd: go test -count=1 github.com/drone/drone/store/perm
- cmd: go test -count=1 github.com/drone/drone/store/repos
- cmd: go test -count=1 github.com/drone/drone/store/secret
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
- cmd: go test -count=1 github.com/drone/drone/store/stage
- cmd: go test -count=1 github.com/drone/drone/store/step
- cmd: go test -count=1 github.com/drone/drone/store/template
- cmd: go test -count=1 github.com/drone/drone/store/user
- cmd: docker kill postgres
silent: true

44
cache/cache.go vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"context"
)
// Cache is an abstraction of a simple cache.
type Cache[K any, V any] interface {
Stats() (int64, int64)
Get(ctx context.Context, key K) (V, error)
}
// ExtendedCache is an extension of the simple cache abstraction that adds mapping functionality.
type ExtendedCache[K comparable, V Identifiable[K]] interface {
Cache[K, V]
Map(ctx context.Context, keys []K) (map[K]V, error)
}
type Identifiable[K comparable] interface {
Identifier() K
}
type Getter[K any, V any] interface {
Find(ctx context.Context, key K) (V, error)
}
type ExtendedGetter[K comparable, V Identifiable[K]] interface {
Getter[K, V]
FindMany(ctx context.Context, keys []K) ([]V, error)
}

69
cache/cache_test.go vendored Normal file
View File

@ -0,0 +1,69 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"reflect"
"testing"
)
func TestDeduplicate(t *testing.T) {
tests := []struct {
name string
input []int
expected []int
}{
{
name: "empty",
input: nil,
expected: nil,
},
{
name: "one-element",
input: []int{1},
expected: []int{1},
},
{
name: "one-element-duplicated",
input: []int{1, 1},
expected: []int{1},
},
{
name: "two-elements",
input: []int{2, 1},
expected: []int{1, 2},
},
{
name: "three-elements",
input: []int{2, 2, 3, 3, 1, 1},
expected: []int{1, 2, 3},
},
{
name: "many-elements",
input: []int{2, 5, 1, 2, 3, 3, 4, 5, 1, 1},
expected: []int{1, 2, 3, 4, 5},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
test.input = deduplicate(test.input)
if want, got := test.expected, test.input; !reflect.DeepEqual(want, got) {
t.Errorf("failed - want=%v, got=%v", want, got)
return
}
})
}
}

37
cache/no_cache.go vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"context"
)
type NoCache[K any, V any] struct {
getter Getter[K, V]
}
func NewNoCache[K any, V any](getter Getter[K, V]) NoCache[K, V] {
return NoCache[K, V]{
getter: getter,
}
}
func (c NoCache[K, V]) Stats() (int64, int64) {
return 0, 0
}
func (c NoCache[K, V]) Get(ctx context.Context, key K) (V, error) {
return c.getter.Find(ctx, key)
}

99
cache/redis_cache.go vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
type Redis[K any, V any] struct {
client redis.UniversalClient
duration time.Duration
getter Getter[K, V]
keyEncoder func(K) string
codec Codec[V]
countHit int64
countMiss int64
}
type Encoder[V any] interface {
Encode(value V) string
}
type Decoder[V any] interface {
Decode(encoded string) (V, error)
}
type Codec[V any] interface {
Encoder[V]
Decoder[V]
}
func NewRedis[K any, V any](
client redis.UniversalClient,
getter Getter[K, V],
keyEncoder func(K) string,
codec Codec[V],
duration time.Duration,
) *Redis[K, V] {
return &Redis[K, V]{
client: client,
duration: duration,
getter: getter,
keyEncoder: keyEncoder,
codec: codec,
countHit: 0,
countMiss: 0,
}
}
// Stats returns number of cache hits and misses and can be used to monitor the cache efficiency.
func (c *Redis[K, V]) Stats() (int64, int64) {
return c.countHit, c.countMiss
}
// Get implements the cache.Cache interface.
func (c *Redis[K, V]) Get(ctx context.Context, key K) (V, error) {
var nothing V
strKey := c.keyEncoder(key)
raw, err := c.client.Get(ctx, strKey).Result()
if err == nil {
c.countHit++
return c.codec.Decode(raw)
}
if err != redis.Nil {
return nothing, err
}
c.countMiss++
item, err := c.getter.Find(ctx, key)
if err != nil {
return nothing, fmt.Errorf("cache: failed to find one: %w", err)
}
err = c.client.Set(ctx, strKey, c.codec.Encode(item), c.duration).Err()
if err != nil {
return nothing, err
}
return item, nil
}

231
cache/ttl_cache.go vendored Normal file
View File

@ -0,0 +1,231 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cache
import (
"context"
"fmt"
"sort"
"sync"
"time"
"golang.org/x/exp/constraints"
)
// TTLCache is a generic TTL based cache that stores objects for the specified period.
// The TTLCache has no maximum capacity, so the idea is to store objects for short period.
// The goal of the TTLCache is to reduce database load.
// Every instance of TTLCache has a background routine that purges stale items.
type TTLCache[K comparable, V any] struct {
mx sync.RWMutex
cache map[K]cacheEntry[V]
purgeStop chan struct{}
getter Getter[K, V]
maxAge time.Duration
countHit int64
countMiss int64
}
// ExtendedTTLCache is an extended version of the TTLCache.
type ExtendedTTLCache[K constraints.Ordered, V Identifiable[K]] struct {
TTLCache[K, V]
getter ExtendedGetter[K, V]
}
type cacheEntry[V any] struct {
added time.Time
data V
}
// New creates a new TTLCache instance and a background routine
// that periodically purges stale items.
func New[K comparable, V any](getter Getter[K, V], maxAge time.Duration) *TTLCache[K, V] {
c := &TTLCache[K, V]{
cache: make(map[K]cacheEntry[V]),
purgeStop: make(chan struct{}),
getter: getter,
maxAge: maxAge,
}
go c.purger()
return c
}
// NewExtended creates a new TTLCacheExtended instance and a background routine
// that periodically purges stale items.
func NewExtended[K constraints.Ordered, V Identifiable[K]](
getter ExtendedGetter[K, V],
maxAge time.Duration,
) *ExtendedTTLCache[K, V] {
c := &ExtendedTTLCache[K, V]{
TTLCache: TTLCache[K, V]{
cache: make(map[K]cacheEntry[V]),
purgeStop: make(chan struct{}),
getter: getter,
maxAge: maxAge,
},
getter: getter,
}
go c.purger()
return c
}
// purger periodically evicts stale items from the Cache.
func (c *TTLCache[K, V]) purger() {
purgeTick := time.NewTicker(time.Minute)
defer purgeTick.Stop()
for {
select {
case <-c.purgeStop:
return
case now := <-purgeTick.C:
c.mx.Lock()
for id, v := range c.cache {
if now.Sub(v.added) >= c.maxAge {
delete(c.cache, id)
}
}
c.mx.Unlock()
}
}
}
// Stop stops the internal purger of stale elements.
func (c *TTLCache[K, V]) Stop() {
close(c.purgeStop)
}
// Stats returns number of cache hits and misses and can be used to monitor the cache efficiency.
func (c *TTLCache[K, V]) Stats() (int64, int64) {
return c.countHit, c.countMiss
}
func (c *TTLCache[K, V]) fetch(key K, now time.Time) (V, bool) {
c.mx.RLock()
defer c.mx.RUnlock()
item, ok := c.cache[key]
if !ok || now.Sub(item.added) > c.maxAge {
c.countMiss++
var nothing V
return nothing, false
}
c.countHit++
// we deliberately don't update the `item.added` timestamp for `now` because
// we want to cache the items only for a short period.
return item.data, true
}
// Map returns map with all objects requested through the slice of IDs.
func (c *ExtendedTTLCache[K, V]) Map(ctx context.Context, keys []K) (map[K]V, error) {
m := make(map[K]V)
now := time.Now()
keys = deduplicate(keys)
// Check what's already available in the cache.
var idx int
for idx < len(keys) {
key := keys[idx]
item, ok := c.fetch(key, now)
if !ok {
idx++
continue
}
// found in cache: Add to the result map and remove the ID from the list.
m[key] = item
keys[idx] = keys[len(keys)-1]
keys = keys[:len(keys)-1]
}
if len(keys) == 0 {
return m, nil
}
// Pull entries from the getter that are not in the cache.
items, err := c.getter.FindMany(ctx, keys)
if err != nil {
return nil, fmt.Errorf("cache: failed to find many: %w", err)
}
c.mx.Lock()
defer c.mx.Unlock()
for _, item := range items {
id := item.Identifier()
m[id] = item
c.cache[id] = cacheEntry[V]{
added: now,
data: item,
}
}
return m, nil
}
// Get returns one object by its ID.
func (c *TTLCache[K, V]) Get(ctx context.Context, key K) (V, error) {
now := time.Now()
var nothing V
item, ok := c.fetch(key, now)
if ok {
return item, nil
}
item, err := c.getter.Find(ctx, key)
if err != nil {
return nothing, fmt.Errorf("cache: failed to find one: %w", err)
}
c.mx.Lock()
c.cache[key] = cacheEntry[V]{
added: now,
data: item,
}
c.mx.Unlock()
return item, nil
}
// deduplicate is a utility function that removes duplicates from slice.
func deduplicate[V constraints.Ordered](slice []V) []V {
if len(slice) <= 1 {
return slice
}
sort.Slice(slice, func(i, j int) bool { return slice[i] < slice[j] })
pointer := 0
for i := 1; i < len(slice); i++ {
if slice[pointer] != slice[i] {
pointer++
slice[pointer] = slice[i]
}
}
return slice[:pointer+1]
}

34
cli/cli.go Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"os"
"github.com/harness/gitness/cli/operations/hooks"
"github.com/harness/gitness/githook"
)
func GetArguments() []string {
command := os.Args[0]
args := os.Args[1:]
// in case of githooks, translate the arguments coming from git to work with gitness.
if gitArgs, fromGit := githook.SanitizeArgsForGit(command, args); fromGit {
return append([]string{hooks.ParamHooks}, gitArgs...)
}
return args
}

View File

@ -0,0 +1,68 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package account
import (
"context"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/cli/textui"
"github.com/harness/gitness/internal/api/controller/user"
"gopkg.in/alecthomas/kingpin.v2"
)
type loginCommand struct {
server string
}
func (c *loginCommand) run(*kingpin.ParseContext) error {
ss := provide.NewSession()
loginIdentifier, password := textui.Credentials()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
in := &user.LoginInput{
LoginIdentifier: loginIdentifier,
Password: password,
}
ts, err := provide.OpenClient(c.server).Login(ctx, in)
if err != nil {
return err
}
return ss.
SetURI(c.server).
// login token always has an expiry date
SetExpiresAt(*ts.Token.ExpiresAt).
SetAccessToken(ts.AccessToken).
Store()
}
// RegisterLogin helper function to register the logout command.
func RegisterLogin(app *kingpin.Application) {
c := &loginCommand{}
cmd := app.Command("login", "login to the remote server").
Action(c.run)
cmd.Arg("server", "server address").
Default(provide.DefaultServerURI).
StringVar(&c.server)
}

View File

@ -0,0 +1,37 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package account
import (
"os"
"github.com/harness/gitness/cli/provide"
"gopkg.in/alecthomas/kingpin.v2"
)
type logoutCommand struct{}
func (c *logoutCommand) run(*kingpin.ParseContext) error {
return os.Remove(provide.Session().Path())
}
// RegisterLogout helper function to register the logout command.
func RegisterLogout(app *kingpin.Application) {
c := &logoutCommand{}
app.Command("logout", "logout from the remote server").
Action(c.run)
}

View File

@ -0,0 +1,78 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package account
import (
"context"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/cli/session"
"github.com/harness/gitness/cli/textui"
"github.com/harness/gitness/internal/api/controller/user"
"gopkg.in/alecthomas/kingpin.v2"
)
type Session interface {
SetURI(uri string) session.Session
SetExpiresAt(expiresAt int64) session.Session
SetAccessToken(token string) session.Session
Path() string
Store() error
}
type registerCommand struct {
server string
}
func (c *registerCommand) run(*kingpin.ParseContext) error {
ss := provide.NewSession()
uid, displayName, email, password := textui.Registration()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
input := &user.RegisterInput{
UID: uid,
Email: email,
DisplayName: displayName,
Password: password,
}
ts, err := provide.OpenClient(c.server).Register(ctx, input)
if err != nil {
return err
}
return ss.
SetURI(c.server).
// register token always has an expiry date
SetExpiresAt(*ts.Token.ExpiresAt).
SetAccessToken(ts.AccessToken).
Store()
}
// RegisterRegister helper function to register the register command.
func RegisterRegister(app *kingpin.Application) {
c := &registerCommand{}
cmd := app.Command("register", "register a user").
Action(c.run)
cmd.Arg("server", "server address").
Default(provide.DefaultServerURI).
StringVar(&c.server)
}

View File

@ -0,0 +1,32 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hooks
import (
"github.com/harness/gitness/githook"
gitnessgithook "github.com/harness/gitness/internal/githook"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
// ParamHooks defines the parameter for the git hooks sub-commands.
ParamHooks = "hooks"
)
func Register(app *kingpin.Application) {
subCmd := app.Command(ParamHooks, "manage git server hooks")
githook.RegisterAll(subCmd, gitnessgithook.LoadFromEnvironment)
}

View File

@ -0,0 +1,59 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package migrate
import (
"context"
"fmt"
"time"
"github.com/harness/gitness/internal/store/database/migrate"
"gopkg.in/alecthomas/kingpin.v2"
)
type commandCurrent struct {
envfile string
}
func (c *commandCurrent) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
db, err := getDB(ctx, c.envfile)
if err != nil {
return err
}
version, err := migrate.Current(ctx, db)
if err != nil {
return err
}
fmt.Println(version)
return nil
}
func registerCurrent(app *kingpin.CmdClause) {
c := &commandCurrent{}
cmd := app.Command("current", "display the current version of the database").
Action(c.run)
cmd.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&c.envfile)
}

View File

@ -0,0 +1,50 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package migrate
import (
"context"
"fmt"
"github.com/harness/gitness/cli/server"
"github.com/harness/gitness/store/database"
"github.com/jmoiron/sqlx"
"github.com/joho/godotenv"
"gopkg.in/alecthomas/kingpin.v2"
)
func getDB(ctx context.Context, envfile string) (*sqlx.DB, error) {
_ = godotenv.Load(envfile)
config, err := server.LoadConfig()
if err != nil {
return nil, fmt.Errorf("failed to load configuration: %w", err)
}
db, err := database.Connect(ctx, config.Database.Driver, config.Database.Datasource)
if err != nil {
return nil, fmt.Errorf("failed to create database handle: %w", err)
}
return db, nil
}
// Register the server command.
func Register(app *kingpin.Application) {
cmd := app.Command("migrate", "database migration tool")
registerCurrent(cmd)
registerTo(cmd)
}

View File

@ -0,0 +1,56 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package migrate
import (
"context"
"time"
"github.com/harness/gitness/internal/store/database/migrate"
"gopkg.in/alecthomas/kingpin.v2"
)
type commandTo struct {
envfile string
version string
}
func (c *commandTo) run(k *kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
db, err := getDB(ctx, c.envfile)
if err != nil {
return err
}
return migrate.To(ctx, db, c.version)
}
func registerTo(app *kingpin.CmdClause) {
c := &commandTo{}
cmd := app.Command("to", "migrates the database to the provided version").
Action(c.run)
cmd.Arg("version", "database version to migrate to").
Required().
StringVar(&c.version)
cmd.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&c.envfile)
}

View File

@ -0,0 +1,97 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package user
import (
"context"
"encoding/json"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/internal/api/controller/user"
"github.com/drone/funcmap"
"github.com/gotidy/ptr"
"gopkg.in/alecthomas/kingpin.v2"
)
const tokenTmpl = `
principalID: {{ .Token.PrincipalID }}
uid: {{ .Token.UID }}
expiresAt: {{ .Token.ExpiresAt }}
token: {{ .AccessToken }}
` //#nosec G101
type createPATCommand struct {
uid string
lifetimeInS int64
json bool
tmpl string
}
func (c *createPATCommand) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
var lifeTime *time.Duration
if c.lifetimeInS > 0 {
lifeTime = ptr.Duration(time.Duration(int64(time.Second) * c.lifetimeInS))
}
in := user.CreateTokenInput{
UID: c.uid,
Lifetime: lifeTime,
}
tokenResp, err := provide.Client().UserCreatePAT(ctx, in)
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(tokenResp)
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, tokenResp)
}
// Register the command.
func registerCreatePAT(app *kingpin.CmdClause) {
c := &createPATCommand{}
cmd := app.Command("pat", "create personal access token").
Action(c.run)
cmd.Arg("uid", "the uid of the token").
Required().StringVar(&c.uid)
cmd.Arg("lifetime", "the lifetime of the token in seconds").
Int64Var(&c.lifetimeInS)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(tokenTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,76 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package user
import (
"context"
"encoding/json"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/drone/funcmap"
"gopkg.in/alecthomas/kingpin.v2"
)
const userTmpl = `
uid: {{ .UID }}
name: {{ .DisplayName }}
email: {{ .Email }}
admin: {{ .Admin }}
`
type command struct {
tmpl string
json bool
}
func (c *command) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
user, err := provide.Client().Self(ctx)
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(user)
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// Register the command.
func registerSelf(app *kingpin.CmdClause) {
c := &command{}
cmd := app.Command("self", "display authenticated user").
Action(c.run)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(userTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,26 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package user
import (
"gopkg.in/alecthomas/kingpin.v2"
)
// Register the command.
func Register(app *kingpin.Application) {
cmd := app.Command("user", "manage currently logged-in user")
registerSelf(cmd)
registerCreatePAT(cmd)
}

View File

@ -0,0 +1,86 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"context"
"encoding/json"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/cli/textui"
"github.com/harness/gitness/types"
"github.com/drone/funcmap"
"gopkg.in/alecthomas/kingpin.v2"
)
type createCommand struct {
email string
admin bool
tmpl string
json bool
}
func (c *createCommand) run(*kingpin.ParseContext) error {
in := &types.User{
Admin: c.admin,
Email: c.email,
Password: textui.Password(),
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
user, err := provide.Client().UserCreate(ctx, in)
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(user)
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// helper function registers the user create command.
func registerCreate(app *kingpin.CmdClause) {
c := &createCommand{}
cmd := app.Command("create", "create a user").
Action(c.run)
cmd.Arg("email", "user email").
Required().
StringVar(&c.email)
cmd.Arg("admin", "user is admin").
BoolVar(&c.admin)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(userTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,47 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"context"
"time"
"github.com/harness/gitness/cli/provide"
"gopkg.in/alecthomas/kingpin.v2"
)
type deleteCommand struct {
email string
}
func (c *deleteCommand) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
return provide.Client().UserDelete(ctx, c.email)
}
// helper function registers the user delete command.
func registerDelete(app *kingpin.CmdClause) {
c := &deleteCommand{}
cmd := app.Command("delete", "delete a user").
Action(c.run)
cmd.Arg("id or email", "user id or email").
Required().
StringVar(&c.email)
}

View File

@ -0,0 +1,74 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"context"
"encoding/json"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/drone/funcmap"
"gopkg.in/alecthomas/kingpin.v2"
)
type findCommand struct {
email string
tmpl string
json bool
}
func (c *findCommand) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
user, err := provide.Client().User(ctx, c.email)
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(user)
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// helper function registers the user find command.
func registerFind(app *kingpin.CmdClause) {
c := &findCommand{}
cmd := app.Command("find", "display user details").
Action(c.run)
cmd.Arg("id or email", "user id or email").
Required().
StringVar(&c.email)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(userTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,92 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"context"
"encoding/json"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/types"
"github.com/drone/funcmap"
"gopkg.in/alecthomas/kingpin.v2"
)
const userTmpl = `
id: {{ .ID }}
email: {{ .Email }}
admin: {{ .Admin }}
`
type listCommand struct {
tmpl string
page int
size int
json bool
}
func (c *listCommand) run(*kingpin.ParseContext) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
list, err := provide.Client().UserList(ctx, types.UserFilter{
Size: c.size,
Page: c.page,
})
if err != nil {
return err
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl + "\n")
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(list)
}
for _, item := range list {
if err = tmpl.Execute(os.Stdout, item); err != nil {
return err
}
}
return nil
}
// helper function registers the user list command.
func registerList(app *kingpin.CmdClause) {
c := &listCommand{}
cmd := app.Command("ls", "display a list of users").
Action(c.run)
cmd.Flag("page", "page number").
IntVar(&c.page)
cmd.Flag("per-page", "page size").
IntVar(&c.size)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(userTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,118 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"context"
"encoding/json"
"fmt"
"os"
"text/template"
"time"
"github.com/harness/gitness/cli/provide"
"github.com/harness/gitness/types"
"github.com/dchest/uniuri"
"github.com/drone/funcmap"
"github.com/gotidy/ptr"
"gopkg.in/alecthomas/kingpin.v2"
)
type updateCommand struct {
id string
email string
admin bool
demote bool
passgen bool
pass string
tmpl string
json bool
}
func (c *updateCommand) run(*kingpin.ParseContext) error {
in := new(types.UserInput)
if v := c.email; v != "" {
in.Email = ptr.String(v)
}
if v := c.pass; v != "" {
in.Password = ptr.String(v)
}
if v := c.admin; v {
in.Admin = ptr.Bool(v)
}
if v := c.demote; v {
in.Admin = ptr.Bool(false)
}
if c.passgen {
const maxRandomChars = 8
v := uniuri.NewLen(maxRandomChars)
in.Password = ptr.String(v)
fmt.Printf("generated temporary password: %s\n", v)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
user, err := provide.Client().UserUpdate(ctx, c.id, in)
if err != nil {
return err
}
if c.json {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
return enc.Encode(user)
}
tmpl, err := template.New("_").Funcs(funcmap.Funcs).Parse(c.tmpl)
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, user)
}
// helper function registers the user update command.
func registerUpdate(app *kingpin.CmdClause) {
c := &updateCommand{}
cmd := app.Command("update", "update a user").
Action(c.run)
cmd.Arg("id or email", "user id or email").
Required().
StringVar(&c.id)
cmd.Flag("email", "update user email").
StringVar(&c.email)
cmd.Flag("password", "update user password").
StringVar(&c.pass)
cmd.Flag("password-gen", "generate and update user password").
BoolVar(&c.passgen)
cmd.Flag("promote", "promote user to admin").
BoolVar(&c.admin)
cmd.Flag("demote", "demote user from admin").
BoolVar(&c.demote)
cmd.Flag("json", "json encode the output").
BoolVar(&c.json)
cmd.Flag("format", "format the output using a Go template").
Default(userTmpl).
Hidden().
StringVar(&c.tmpl)
}

View File

@ -0,0 +1,29 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package users
import (
"gopkg.in/alecthomas/kingpin.v2"
)
// Register the command.
func Register(app *kingpin.Application) {
cmd := app.Command("users", "manage users")
registerFind(cmd)
registerList(cmd)
registerCreate(cmd)
registerUpdate(cmd)
registerDelete(cmd)
}

101
cli/provide/provider.go Normal file
View File

@ -0,0 +1,101 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package provide
import (
"errors"
"io/fs"
"os"
"path/filepath"
"github.com/harness/gitness/cli/session"
"github.com/harness/gitness/client"
"github.com/adrg/xdg"
"github.com/rs/zerolog/log"
)
const DefaultServerURI = "http://localhost:3000"
func NewSession() session.Session {
ss, err := newSession()
if err != nil {
log.Err(err).Msg("failed to get active session")
os.Exit(1)
}
return ss
}
func Session() session.Session {
ss, err := loadSession()
if err != nil {
log.Err(err).Msg("failed to get active session")
os.Exit(1)
}
return ss
}
func Client() client.Client {
return newClient(Session())
}
func OpenClient(uri string) client.Client {
return newClient(session.Session{URI: uri})
}
func sessionPath() (string, error) {
return xdg.ConfigFile(filepath.Join("app", "config.json"))
}
func newSession() (session.Session, error) {
path, err := sessionPath()
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return session.Session{}, err
}
return session.New(path).SetURI(DefaultServerURI), nil
}
func loadSession() (session.Session, error) {
path, err := sessionPath()
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return session.Session{URI: DefaultServerURI}, nil
}
return session.Session{}, err
}
ss, err := session.LoadFromPath(path)
if err != nil {
return session.Session{}, err
}
if ss.URI == "" {
ss = ss.SetURI(DefaultServerURI)
}
return ss, nil
}
func newClient(ss session.Session) client.Client {
httpClient := client.NewToken(ss.URI, ss.AccessToken)
if os.Getenv("DEBUG") == "true" {
httpClient.SetDebug(true)
}
return httpClient
}

195
cli/server/config.go Normal file
View File

@ -0,0 +1,195 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"fmt"
"os"
"path/filepath"
"unicode"
"github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/gitrpc/server"
"github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/lock"
"github.com/harness/gitness/store/database"
"github.com/harness/gitness/types"
"github.com/kelseyhightower/envconfig"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
// LoadConfig returns the system configuration from the
// host environment.
func LoadConfig() (*types.Config, error) {
config := new(types.Config)
err := envconfig.Process("", config)
if err != nil {
return nil, err
}
config.InstanceID, err = getSanitizedMachineName()
if err != nil {
return nil, fmt.Errorf("unable to ensure that instance ID is set in config: %w", err)
}
return config, nil
}
// getSanitizedMachineName gets the name of the machine and returns it in sanitized format.
func getSanitizedMachineName() (string, error) {
// use the hostname as default id of the instance
hostName, err := os.Hostname()
if err != nil {
return "", err
}
// Always cast to lower and remove all unwanted chars
// NOTE: this could theoretically lead to overlaps, then it should be passed explicitly
// NOTE: for k8s names/ids below modifications are all noops
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/
// The following code will:
// * remove invalid runes
// * remove diacritical marks (ie "smörgåsbord" to "smorgasbord")
// * lowercase A-Z to a-z
// * leave only a-z, 0-9, '-', '.' and replace everything else with '_'
hostName, _, err = transform.String(
transform.Chain(
norm.NFD,
runes.ReplaceIllFormed(),
runes.Remove(runes.In(unicode.Mn)),
runes.Map(func(r rune) rune {
switch {
case 'A' <= r && r <= 'Z':
return r + 32
case 'a' <= r && r <= 'z':
return r
case '0' <= r && r <= '9':
return r
case r == '-', r == '.':
return r
default:
return '_'
}
}),
norm.NFC),
hostName)
if err != nil {
return "", err
}
return hostName, nil
}
// ProvideDatabaseConfig loads the database config from the main config.
func ProvideDatabaseConfig(config *types.Config) database.Config {
return database.Config{
Driver: config.Database.Driver,
Datasource: config.Database.Datasource,
}
}
// ProvideGitRPCServerConfig loads the gitrpc server config from the environment.
// It backfills certain config elements to work with cmdone.
func ProvideGitRPCServerConfig() (server.Config, error) {
config := server.Config{}
err := envconfig.Process("", &config)
if err != nil {
return server.Config{}, fmt.Errorf("failed to load gitrpc server config: %w", err)
}
if config.GitHookPath == "" {
var executablePath string
executablePath, err = os.Executable()
if err != nil {
return server.Config{}, fmt.Errorf("failed to get path of current executable: %w", err)
}
config.GitHookPath = executablePath
}
if config.GitRoot == "" {
var homedir string
homedir, err = os.UserHomeDir()
if err != nil {
return server.Config{}, err
}
config.GitRoot = filepath.Join(homedir, ".gitrpc")
}
return config, nil
}
// ProvideGitRPCClientConfig loads the gitrpc client config from the environment.
func ProvideGitRPCClientConfig() (gitrpc.Config, error) {
config := gitrpc.Config{}
err := envconfig.Process("", &config)
if err != nil {
return gitrpc.Config{}, fmt.Errorf("failed to load gitrpc client config: %w", err)
}
return config, nil
}
// ProvideEventsConfig loads the events config from the environment.
func ProvideEventsConfig() (events.Config, error) {
config := events.Config{}
err := envconfig.Process("", &config)
if err != nil {
return events.Config{}, fmt.Errorf("failed to load events config: %w", err)
}
return config, nil
}
// ProvideWebhookConfig loads the webhook service config from the main config.
func ProvideWebhookConfig(config *types.Config) webhook.Config {
return webhook.Config{
UserAgentIdentity: config.Webhook.UserAgentIdentity,
HeaderIdentity: config.Webhook.HeaderIdentity,
EventReaderName: config.InstanceID,
Concurrency: config.Webhook.Concurrency,
MaxRetries: config.Webhook.MaxRetries,
AllowPrivateNetwork: config.Webhook.AllowPrivateNetwork,
AllowLoopback: config.Webhook.AllowLoopback,
}
}
// ProvideTriggerConfig loads the trigger service config from the main config.
func ProvideTriggerConfig(config *types.Config) trigger.Config {
return trigger.Config{
EventReaderName: config.InstanceID,
Concurrency: config.Webhook.Concurrency,
MaxRetries: config.Webhook.MaxRetries,
}
}
// ProvideLockConfig generates the `lock` package config from the gitness config.
func ProvideLockConfig(config *types.Config) lock.Config {
return lock.Config{
App: config.Lock.AppNamespace,
Namespace: config.Lock.DefaultNamespace,
Provider: lock.Provider(config.Lock.Provider),
Expiry: config.Lock.Expiry,
Tries: config.Lock.Tries,
RetryDelay: config.Lock.RetryDelay,
DriftFactor: config.Lock.DriftFactor,
TimeoutFactor: config.Lock.TimeoutFactor,
}
}

54
cli/server/redis.go Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"strings"
"github.com/harness/gitness/types"
"github.com/go-redis/redis/v8"
)
// ProvideRedis provides a redis client based on the configuration.
// TODO: add support for TLS
func ProvideRedis(config *types.Config) (redis.UniversalClient, error) {
if config.Redis.SentinelMode {
addrs := strings.Split(config.Redis.SentinelEndpoint, ",")
failoverOptions := &redis.FailoverOptions{
MasterName: config.Redis.SentinelMaster,
SentinelAddrs: addrs,
MaxRetries: config.Redis.MaxRetries,
MinIdleConns: config.Redis.MinIdleConnections,
}
if config.Redis.Password != "" {
failoverOptions.Password = config.Redis.Password
}
return redis.NewFailoverClient(failoverOptions), nil
}
options := &redis.Options{
Addr: config.Redis.Endpoint,
MaxRetries: config.Redis.MaxRetries,
MinIdleConns: config.Redis.MinIdleConnections,
}
if config.Redis.Password != "" {
options.Password = config.Redis.Password
}
return redis.NewClient(options), nil
}

229
cli/server/server.go Normal file
View File

@ -0,0 +1,229 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/harness/gitness/profiler"
"github.com/harness/gitness/types"
"github.com/harness/gitness/version"
"github.com/drone/runner-go/logger"
"github.com/joho/godotenv"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"gopkg.in/alecthomas/kingpin.v2"
)
type command struct {
envfile string
enableGitRPC bool
enableCI bool
initializer func(context.Context, *types.Config) (*System, error)
}
func (c *command) run(*kingpin.ParseContext) error {
// Create context that listens for the interrupt signal from the OS.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
// load environment variables from file.
// no error handling needed when file is not present
_ = godotenv.Load(c.envfile)
// create the system configuration store by loading
// data from the environment.
config, err := LoadConfig()
if err != nil {
return fmt.Errorf("encountered an error while loading configuration: %w", err)
}
// configure the log level
SetupLogger(config)
// configure profiler
SetupProfiler(config)
// add logger to context
log := log.Logger.With().Logger()
ctx = log.WithContext(ctx)
// initialize system
system, err := c.initializer(ctx, config)
if err != nil {
return fmt.Errorf("encountered an error while wiring the system: %w", err)
}
// bootstrap the system
err = system.bootstrap(ctx)
if err != nil {
return fmt.Errorf("encountered an error while bootstrapping the system: %w", err)
}
// gCtx is canceled if any of the following occurs:
// - any go routine launched with g encounters an error
// - ctx is canceled
g, gCtx := errgroup.WithContext(ctx)
g.Go(func() error {
// initialize metric collector
if system.services.MetricCollector != nil {
system.services.MetricCollector.Register(gCtx)
}
return system.services.JobScheduler.Run(gCtx)
})
// start server
gHTTP, shutdownHTTP := system.server.ListenAndServe()
g.Go(gHTTP.Wait)
if c.enableCI {
// start populating plugins
g.Go(func() error {
err := system.pluginManager.Populate(ctx)
if err != nil {
log.Error().Err(err).Msg("could not populate plugins")
}
return nil
})
// start poller for CI build executions.
g.Go(func() error {
log := logrus.New()
log.Out = os.Stdout
log.Level = logrus.DebugLevel // print all debug logs in common runner code.
ctx = logger.WithContext(ctx, logger.Logrus(log.WithContext(ctx)))
system.poller.Poll(ctx, config.CI.ParallelWorkers)
return nil
})
}
log.Info().
Str("port", config.Server.HTTP.Bind).
Str("revision", version.GitCommit).
Str("repository", version.GitRepository).
Stringer("version", version.Version).
Msg("server started")
if c.enableGitRPC {
// start grpc server
g.Go(system.gitRPCServer.Start)
log.Info().Msg("gitrpc server started")
// run the gitrpc cron jobs
g.Go(func() error {
return system.gitRPCCronMngr.Run(ctx)
})
log.Info().Msg("gitrpc cron manager subroutine started")
}
// wait until the error group context is done
<-gCtx.Done()
// restore default behavior on the interrupt signal and notify user of shutdown.
stop()
log.Info().Msg("shutting down gracefully (press Ctrl+C again to force)")
// shutdown servers gracefully
shutdownCtx, cancel := context.WithTimeout(context.Background(), config.GracefulShutdownTime)
defer cancel()
if sErr := shutdownHTTP(shutdownCtx); sErr != nil {
log.Err(sErr).Msg("failed to shutdown http server gracefully")
}
if c.enableGitRPC {
if rpcErr := system.gitRPCServer.Stop(); rpcErr != nil {
log.Err(rpcErr).Msg("failed to shutdown grpc server gracefully")
}
}
system.services.JobScheduler.WaitJobsDone(shutdownCtx)
log.Info().Msg("wait for subroutines to complete")
err = g.Wait()
return err
}
// SetupLogger configures the global logger from the loaded configuration.
func SetupLogger(config *types.Config) {
// configure the log level
switch {
case config.Trace:
zerolog.SetGlobalLevel(zerolog.TraceLevel)
case config.Debug:
zerolog.SetGlobalLevel(zerolog.DebugLevel)
default:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}
// configure time format (ignored if running in terminal)
zerolog.TimeFieldFormat = time.RFC3339Nano
// if the terminal is a tty we should output the
// logs in pretty format
if isatty.IsTerminal(os.Stdout.Fd()) {
log.Logger = log.Output(
zerolog.ConsoleWriter{
Out: os.Stderr,
NoColor: false,
TimeFormat: "15:04:05.999",
},
)
}
}
func SetupProfiler(config *types.Config) {
profilerType, parsed := profiler.ParseType(config.Profiler.Type)
if !parsed {
log.Info().Msgf("No valid profiler so skipping profiling ['%s']", config.Profiler.Type)
return
}
gitnessProfiler, _ := profiler.New(profilerType)
gitnessProfiler.StartProfiling(config.Profiler.ServiceName, version.Version.String())
}
// Register the server command.
func Register(app *kingpin.Application, initializer func(context.Context, *types.Config) (*System, error)) {
c := new(command)
c.initializer = initializer
cmd := app.Command("server", "starts the server").
Action(c.run)
cmd.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&c.envfile)
cmd.Flag("enable-gitrpc", "start the gitrpc server").
Default("true").
Envar("ENABLE_GITRPC").
BoolVar(&c.enableGitRPC)
cmd.Flag("enable-ci", "start ci runners for build executions").
Default("true").
Envar("ENABLE_CI").
BoolVar(&c.enableCI)
}

52
cli/server/system.go Normal file
View File

@ -0,0 +1,52 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
gitrpcserver "github.com/harness/gitness/gitrpc/server"
gitrpccron "github.com/harness/gitness/gitrpc/server/cron"
"github.com/harness/gitness/internal/bootstrap"
"github.com/harness/gitness/internal/pipeline/plugin"
"github.com/harness/gitness/internal/server"
"github.com/harness/gitness/internal/services"
"github.com/drone/runner-go/poller"
)
// System stores high level System sub-routines.
type System struct {
bootstrap bootstrap.Bootstrap
server *server.Server
gitRPCServer *gitrpcserver.GRPCServer
pluginManager *plugin.PluginManager
poller *poller.Poller
services services.Services
gitRPCCronMngr *gitrpccron.Manager
}
// NewSystem returns a new system structure.
func NewSystem(bootstrap bootstrap.Bootstrap, server *server.Server, poller *poller.Poller,
gitRPCServer *gitrpcserver.GRPCServer, pluginManager *plugin.PluginManager,
gitrpccron *gitrpccron.Manager, services services.Services) *System {
return &System{
bootstrap: bootstrap,
server: server,
poller: poller,
gitRPCServer: gitRPCServer,
pluginManager: pluginManager,
services: services,
gitRPCCronMngr: gitrpccron,
}
}

95
cli/session/session.go Normal file
View File

@ -0,0 +1,95 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package session
import (
"encoding/json"
"errors"
"fmt"
"os"
"time"
)
var (
ErrTokenExpired = errors.New("token is expired, please login")
)
type Session struct {
path string
URI string `json:"uri"`
ExpiresAt int64 `json:"expires_at"`
AccessToken string `json:"access_token"`
}
// New creates a new session to be stores to the provided path.
func New(path string) Session {
return Session{
path: path,
}
}
// LoadFromPath loads an existing session from a file.
func LoadFromPath(path string) (Session, error) {
session := Session{
path: path,
}
data, err := os.ReadFile(path)
if err != nil {
return session, fmt.Errorf("failed to read session from file: %w", err)
}
if err = json.Unmarshal(data, &session); err != nil {
return session, fmt.Errorf("failed to deserialize session: %w", err)
}
if time.Now().Unix() > session.ExpiresAt {
return session, ErrTokenExpired
}
return session, nil
}
// Store stores an existing session to the default file.
func (s Session) Store() error {
data, err := json.Marshal(s)
if err != nil {
return fmt.Errorf("failed to serialize session: %w", err)
}
err = os.WriteFile(s.path, data, 0o600)
if err != nil {
return fmt.Errorf("failed to write session to file: %w", err)
}
return nil
}
func (s Session) SetURI(uri string) Session {
s.URI = uri
return s
}
func (s Session) SetExpiresAt(expiresAt int64) Session {
s.ExpiresAt = expiresAt
return s
}
func (s Session) SetAccessToken(token string) Session {
s.AccessToken = token
return s
}
func (s Session) Path() string {
return s.path
}

49
cli/swagger.go Normal file
View File

@ -0,0 +1,49 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"os"
"github.com/harness/gitness/internal/api/openapi"
"gopkg.in/alecthomas/kingpin.v2"
)
type swaggerCommand struct {
path string
}
func (c *swaggerCommand) run(*kingpin.ParseContext) error {
spec := openapi.Generate()
data, _ := spec.MarshalYAML()
if c.path == "" {
os.Stdout.Write(data)
return nil
}
return os.WriteFile(c.path, data, 0o600)
}
// helper function to register the swagger command.
func RegisterSwagger(app *kingpin.Application) {
c := new(swaggerCommand)
cmd := app.Command("swagger", "generate swagger file").
Hidden().
Action(c.run)
cmd.Arg("path", "path to save swagger file").
StringVar(&c.path)
}

84
cli/textui/input.go Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package textui
import (
"bufio"
"fmt"
"os"
"strings"
"syscall"
"golang.org/x/term"
)
// Registration returns the userID, displayName, email and password from stdin.
func Registration() (string, string, string, string) {
return UserID(), DisplayName(), Email(), Password()
}
// Credentials returns the login identifier and password from stdin.
func Credentials() (string, string) {
return LoginIdentifier(), Password()
}
// UserID returns the user ID from stdin.
func UserID() string {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter User ID: ")
uid, _ := reader.ReadString('\n')
return strings.TrimSpace(uid)
}
// LoginIdentifier returns the login identifier from stdin.
func LoginIdentifier() string {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter User ID or Email: ")
id, _ := reader.ReadString('\n')
return strings.TrimSpace(id)
}
// DisplayName returns the display name from stdin.
func DisplayName() string {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Display Name: ")
name, _ := reader.ReadString('\n')
return strings.TrimSpace(name)
}
// Email returns the email from stdin.
func Email() string {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Email: ")
email, _ := reader.ReadString('\n')
return strings.TrimSpace(email)
}
// Password returns the password from stdin.
func Password() string {
fmt.Print("Enter Password: ")
passwordb, _ := term.ReadPassword(syscall.Stdin)
password := string(passwordb)
return strings.TrimSpace(password)
}

250
client/client.go Normal file
View File

@ -0,0 +1,250 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
"github.com/harness/gitness/internal/api/controller/user"
"github.com/harness/gitness/types"
"github.com/harness/gitness/version"
"github.com/rs/zerolog/log"
)
// ensure HTTPClient implements Client interface.
var _ Client = (*HTTPClient)(nil)
// HTTPClient provides an HTTP client for interacting
// with the remote API.
type HTTPClient struct {
client *http.Client
base string
token string
debug bool
}
// New returns a client at the specified url.
func New(uri string) *HTTPClient {
return NewToken(uri, "")
}
// NewToken returns a client at the specified url that
// authenticates all outbound requests with the given token.
func NewToken(uri, token string) *HTTPClient {
return &HTTPClient{http.DefaultClient, uri, token, false}
}
// SetClient sets the default http client. This can be
// used in conjunction with golang.org/x/oauth2 to
// authenticate requests to the server.
func (c *HTTPClient) SetClient(client *http.Client) {
c.client = client
}
// SetDebug sets the debug flag. When the debug flag is
// true, the http.Resposne body to stdout which can be
// helpful when debugging.
func (c *HTTPClient) SetDebug(debug bool) {
c.debug = debug
}
// Login authenticates the user and returns a JWT token.
func (c *HTTPClient) Login(ctx context.Context, input *user.LoginInput) (*types.TokenResponse, error) {
out := new(types.TokenResponse)
uri := fmt.Sprintf("%s/api/v1/login", c.base)
err := c.post(ctx, uri, true, input, out)
return out, err
}
// Register registers a new user and returns a JWT token.
func (c *HTTPClient) Register(ctx context.Context, input *user.RegisterInput) (*types.TokenResponse, error) {
out := new(types.TokenResponse)
uri := fmt.Sprintf("%s/api/v1/register", c.base)
err := c.post(ctx, uri, true, input, out)
return out, err
}
//
// User Endpoints
//
// Self returns the currently authenticated user.
func (c *HTTPClient) Self(ctx context.Context) (*types.User, error) {
out := new(types.User)
uri := fmt.Sprintf("%s/api/v1/user", c.base)
err := c.get(ctx, uri, out)
return out, err
}
// UserCreatePAT creates a new PAT for the user.
func (c *HTTPClient) UserCreatePAT(ctx context.Context, in user.CreateTokenInput) (*types.TokenResponse, error) {
out := new(types.TokenResponse)
uri := fmt.Sprintf("%s/api/v1/user/tokens", c.base)
err := c.post(ctx, uri, false, in, out)
return out, err
}
// User returns a user by ID or email.
func (c *HTTPClient) User(ctx context.Context, key string) (*types.User, error) {
out := new(types.User)
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
err := c.get(ctx, uri, out)
return out, err
}
// UserList returns a list of all registered users.
func (c *HTTPClient) UserList(ctx context.Context, params types.UserFilter) ([]types.User, error) {
out := []types.User{}
uri := fmt.Sprintf("%s/api/v1/users?page=%d&limit=%d", c.base, params.Page, params.Size)
err := c.get(ctx, uri, &out)
return out, err
}
// UserCreate creates a new user account.
func (c *HTTPClient) UserCreate(ctx context.Context, user *types.User) (*types.User, error) {
out := new(types.User)
uri := fmt.Sprintf("%s/api/v1/users", c.base)
err := c.post(ctx, uri, false, user, out)
return out, err
}
// UserUpdate updates a user account by ID or email.
func (c *HTTPClient) UserUpdate(ctx context.Context, key string, user *types.UserInput) (*types.User, error) {
out := new(types.User)
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
err := c.patch(ctx, uri, user, out)
return out, err
}
// UserDelete deletes a user account by ID or email.
func (c *HTTPClient) UserDelete(ctx context.Context, key string) error {
uri := fmt.Sprintf("%s/api/v1/users/%s", c.base, key)
err := c.delete(ctx, uri)
return err
}
//
// http request helper functions
//
// helper function for making an http GET request.
func (c *HTTPClient) get(ctx context.Context, rawurl string, out interface{}) error {
return c.do(ctx, rawurl, "GET", false, nil, out)
}
// helper function for making an http POST request.
func (c *HTTPClient) post(ctx context.Context, rawurl string, noToken bool, in, out interface{}) error {
return c.do(ctx, rawurl, "POST", noToken, in, out)
}
// helper function for making an http PATCH request.
func (c *HTTPClient) patch(ctx context.Context, rawurl string, in, out interface{}) error {
return c.do(ctx, rawurl, "PATCH", false, in, out)
}
// helper function for making an http DELETE request.
func (c *HTTPClient) delete(ctx context.Context, rawurl string) error {
return c.do(ctx, rawurl, "DELETE", false, nil, nil)
}
// helper function to make an http request.
func (c *HTTPClient) do(ctx context.Context, rawurl, method string, noToken bool, in, out interface{}) error {
// executes the http request and returns the body as
// and io.ReadCloser
body, err := c.stream(ctx, rawurl, method, noToken, in, out)
if body != nil {
defer func(body io.ReadCloser) {
_ = body.Close()
}(body)
}
if err != nil {
return err
}
// if a json response is expected, parse and return
// the json response.
if out != nil {
return json.NewDecoder(body).Decode(out)
}
return nil
}
// helper function to stream a http request.
func (c *HTTPClient) stream(ctx context.Context, rawurl, method string, noToken bool,
in, _ interface{}) (io.ReadCloser, error) {
uri, err := url.Parse(rawurl)
if err != nil {
return nil, err
}
// if we are posting or putting data, we need to
// write it to the body of the request.
var buf io.ReadWriter
if in != nil {
buf = &bytes.Buffer{}
if err = json.NewEncoder(buf).Encode(in); err != nil {
return nil, err
}
}
// creates a new http request.
req, err := http.NewRequestWithContext(ctx, method, uri.String(), buf)
if err != nil {
return nil, err
}
if in != nil {
req.Header.Set("Content-Type", "application/json")
}
if !noToken && c.token != "" {
req.Header.Set("Authorization", "Bearer "+c.token)
}
if _, ok := in.(*url.Values); ok {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
// include the client version information in the
// http accept header for debugging purposes.
req.Header.Set("Accept", "application/json;version="+version.Version.String())
// send the http request.
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
if c.debug {
dump, _ := httputil.DumpResponse(resp, true)
log.Debug().Msgf("method %s, url %s", method, rawurl)
log.Debug().Msg(string(dump))
}
if resp.StatusCode >= http.StatusMultipleChoices {
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
err = &remoteError{}
if decodeErr := json.NewDecoder(resp.Body).Decode(err); decodeErr != nil {
return nil, decodeErr
}
return nil, err
}
return resp.Body, nil
}

63
client/interface.go Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
"context"
"github.com/harness/gitness/internal/api/controller/user"
"github.com/harness/gitness/types"
)
// Client to access the remote APIs.
type Client interface {
// Login authenticates the user and returns a JWT token.
Login(ctx context.Context, input *user.LoginInput) (*types.TokenResponse, error)
// Register registers a new user and returns a JWT token.
Register(ctx context.Context, input *user.RegisterInput) (*types.TokenResponse, error)
// Self returns the currently authenticated user.
Self(ctx context.Context) (*types.User, error)
// User returns a user by ID or email.
User(ctx context.Context, key string) (*types.User, error)
// UserList returns a list of all registered users.
UserList(ctx context.Context, params types.UserFilter) ([]types.User, error)
// UserCreate creates a new user account.
UserCreate(ctx context.Context, user *types.User) (*types.User, error)
// UserUpdate updates a user account by ID or email.
UserUpdate(ctx context.Context, key string, input *types.UserInput) (*types.User, error)
// UserDelete deletes a user account by ID or email.
UserDelete(ctx context.Context, key string) error
// UserCreatePAT creates a new PAT for the user.
UserCreatePAT(ctx context.Context, in user.CreateTokenInput) (*types.TokenResponse, error)
}
// remoteError store the error payload returned
// fro the remote API.
type remoteError struct {
Message string `json:"message"`
}
// Error returns the error message.
func (e *remoteError) Error() string {
return e.Message
}

View File

@ -1,123 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bootstrap
import (
"context"
"errors"
"time"
"github.com/dchest/uniuri"
"github.com/drone/drone/core"
"github.com/drone/drone/logger"
"github.com/sirupsen/logrus"
)
var errMissingToken = errors.New("You must provide the machine account token")
// New returns a new account bootstrapper.
func New(users core.UserStore) *Bootstrapper {
return &Bootstrapper{
users: users,
}
}
// Bootstrapper bootstraps the system with the initial account.
type Bootstrapper struct {
users core.UserStore
}
// Bootstrap creates the user account. If the account already exists,
// no account is created, and a nil error is returned.
func (b *Bootstrapper) Bootstrap(ctx context.Context, user *core.User) error {
if user.Login == "" {
return nil
}
log := logrus.WithFields(
logrus.Fields{
"login": user.Login,
"admin": user.Admin,
"machine": user.Machine,
"token": user.Hash,
},
)
log.Debugln("bootstrap: create account")
existingUser, err := b.users.FindLogin(ctx, user.Login)
if err == nil {
ctx = logger.WithContext(ctx, log)
return b.update(ctx, user, existingUser)
}
if user.Machine && user.Hash == "" {
log.Errorln("bootstrap: cannot create account, missing token")
return errMissingToken
}
user.Active = true
user.Created = time.Now().Unix()
user.Updated = time.Now().Unix()
if user.Hash == "" {
user.Hash = uniuri.NewLen(32)
}
err = b.users.Create(ctx, user)
if err != nil {
log = log.WithError(err)
log.Errorln("bootstrap: cannot create account")
return err
}
log = log.WithField("token", user.Hash)
log.Infoln("bootstrap: account created")
return nil
}
func (b *Bootstrapper) update(ctx context.Context, src, dst *core.User) error {
log := logger.FromContext(ctx)
log.Debugln("bootstrap: updating account")
var updated bool
if src.Hash != dst.Hash && src.Hash != "" {
log.Infoln("bootstrap: found updated user token")
dst.Hash = src.Hash
updated = true
}
if src.Machine != dst.Machine {
log.Infoln("bootstrap: found updated machine flag")
dst.Machine = src.Machine
updated = true
}
if src.Admin != dst.Admin {
log.Infoln("bootstrap: found updated admin flag")
dst.Admin = src.Admin
updated = true
}
if !updated {
log.Debugln("bootstrap: account already up-to-date")
return nil
}
dst.Updated = time.Now().Unix()
err := b.users.Update(ctx, dst)
if err != nil {
log = log.WithError(err)
log.Errorln("bootstrap: cannot update account")
return err
}
log.Infoln("bootstrap: account successfully updated")
return nil
}

View File

@ -1,170 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.
package bootstrap
import (
"context"
"database/sql"
"io/ioutil"
"testing"
"github.com/drone/drone/core"
"github.com/drone/drone/mock"
"github.com/dchest/uniuri"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus"
)
var noContext = context.TODO()
func init() {
logrus.SetOutput(ioutil.Discard)
}
func TestBootstrap(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: true,
Admin: true,
Hash: uniuri.NewLen(32),
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(nil, sql.ErrNoRows)
store.EXPECT().Create(gomock.Any(), dummyUser).Return(nil)
err := New(store).Bootstrap(noContext, dummyUser)
if err != nil {
t.Error(err)
}
}
func TestBootstrap_GenerateHash(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: false,
Admin: true,
Hash: "",
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(nil, sql.ErrNoRows)
store.EXPECT().Create(gomock.Any(), dummyUser).Return(nil)
err := New(store).Bootstrap(noContext, dummyUser)
if err != nil {
t.Error(err)
}
if got, want := len(dummyUser.Hash), 32; got != want {
t.Errorf("Want generated hash length %d, got %d", want, got)
}
}
func TestBootstrap_Empty(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "",
}
store := mock.NewMockUserStore(controller)
err := New(store).Bootstrap(noContext, dummyUser)
if err != nil {
t.Error(err)
}
}
func TestBootstrap_Exists_WithoutUpdates(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: true,
Admin: true,
Hash: uniuri.NewLen(32),
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(dummyUser, nil)
err := New(store).Bootstrap(noContext, dummyUser)
if err != nil {
t.Error(err)
}
}
func TestBootstrap_Exists_WithUpdates(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: true,
Admin: true,
Hash: uniuri.NewLen(32),
}
existingUser := &core.User{
Login: "octocat",
Machine: false,
Admin: false,
Hash: uniuri.NewLen(32),
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(existingUser, nil)
store.EXPECT().Update(gomock.Any(), existingUser).Return(nil)
err := New(store).Bootstrap(noContext, dummyUser)
if err != nil {
t.Error(err)
}
}
func TestBootstrap_MissingTokenError(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: true,
Admin: true,
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(nil, sql.ErrNoRows)
err := New(store).Bootstrap(noContext, dummyUser)
if err != errMissingToken {
t.Errorf("Expect missing token error")
}
}
func TestBootstrap_CreateError(t *testing.T) {
controller := gomock.NewController(t)
defer controller.Finish()
dummyUser := &core.User{
Login: "octocat",
Machine: true,
Admin: true,
Hash: uniuri.NewLen(32),
}
store := mock.NewMockUserStore(controller)
store.EXPECT().FindLogin(gomock.Any(), dummyUser.Login).Return(nil, sql.ErrNoRows)
store.EXPECT().Create(gomock.Any(), dummyUser).Return(sql.ErrConnDone)
err := New(store).Bootstrap(noContext, dummyUser)
if err != sql.ErrConnDone {
t.Errorf("Expect error creating user")
}
}

View File

@ -1,644 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"errors"
"fmt"
"os"
"strings"
"time"
"github.com/dchest/uniuri"
"github.com/dustin/go-humanize"
"github.com/kelseyhightower/envconfig"
"gopkg.in/yaml.v2"
)
// IMPORTANT please do not add new configuration parameters unless it has
// been discussed on the mailing list. We are attempting to reduce the
// number of configuration parameters, and may reject pull requests that
// introduce new parameters. (mailing list https://community.harness.io)
// default runner hostname.
var hostname string
func init() {
hostname, _ = os.Hostname()
if hostname == "" {
hostname = "localhost"
}
}
type (
// Config provides the system configuration.
Config struct {
License string `envconfig:"DRONE_LICENSE"`
Authn Authentication
Agent Agent
AzureBlob AzureBlob
Convert Convert
Cleanup Cleanup
Cron Cron
Cloning Cloning
Database Database
Datadog Datadog
Docker Docker
HTTP HTTP
Jsonnet Jsonnet
Starlark Starlark
Logging Logging
Prometheus Prometheus
Proxy Proxy
Redis Redis
Registration Registration
Registries Registries
Repository Repository
Runner Runner
RPC RPC
S3 S3
Secrets Secrets
Server Server
Session Session
Status Status
Users Users
Validate Validate
Webhook Webhook
Yaml Yaml
// Remote configurations
Bitbucket Bitbucket
Gitea Gitea
Github Github
GitLab GitLab
Gogs Gogs
Stash Stash
Gitee Gitee
}
// Cloning provides the cloning configuration.
Cloning struct {
AlwaysAuth bool `envconfig:"DRONE_GIT_ALWAYS_AUTH"`
Username string `envconfig:"DRONE_GIT_USERNAME"`
Password string `envconfig:"DRONE_GIT_PASSWORD"`
Image string `envconfig:"DRONE_GIT_IMAGE"`
Pull string `envconfig:"DRONE_GIT_IMAGE_PULL" default:"IfNotExists"`
}
Cleanup struct {
Disabled bool `envconfig:"DRONE_CLEANUP_DISABLED"`
Interval time.Duration `envconfig:"DRONE_CLEANUP_INTERVAL" default:"24h"`
Running time.Duration `envconfig:"DRONE_CLEANUP_DEADLINE_RUNNING" default:"24h"`
Pending time.Duration `envconfig:"DRONE_CLEANUP_DEADLINE_PENDING" default:"24h"`
Buffer time.Duration `envconfig:"DRONE_CLEANUP_BUFFER" default:"30m"`
}
// Cron provides the cron configuration.
Cron struct {
Disabled bool `envconfig:"DRONE_CRON_DISABLED"`
Interval time.Duration `envconfig:"DRONE_CRON_INTERVAL" default:"30m"`
}
// Database provides the database configuration.
Database struct {
Driver string `envconfig:"DRONE_DATABASE_DRIVER" default:"sqlite3"`
Datasource string `envconfig:"DRONE_DATABASE_DATASOURCE" default:"core.sqlite"`
Secret string `envconfig:"DRONE_DATABASE_SECRET"`
MaxConnections int `envconfig:"DRONE_DATABASE_MAX_CONNECTIONS" default:"0"`
// Feature flag
LegacyBatch bool `envconfig:"DRONE_DATABASE_LEGACY_BATCH"`
// Feature flag
EncryptUserTable bool `envconfig:"DRONE_DATABASE_ENCRYPT_USER_TABLE"`
EncryptMixedContent bool `envconfig:"DRONE_DATABASE_ENCRYPT_MIXED_MODE"`
}
// Docker provides docker configuration
Docker struct {
Config string `envconfig:"DRONE_DOCKER_CONFIG"`
}
// Datadog provides datadog configuration
Datadog struct {
Enabled bool `envconfig:"DRONE_DATADOG_ENABLED"`
Endpoint string `envconfig:"DRONE_DATADOG_ENDPOINT"`
Token string `envconfig:"DRONE_DATADOG_TOKEN"`
}
// Jsonnet configures the jsonnet plugin
Jsonnet struct {
Enabled bool `envconfig:"DRONE_JSONNET_ENABLED"`
ImportLimit int `envconfig:"DRONE_JSONNET_IMPORT_LIMIT" default:"0"`
}
// Starlark configures the starlark plugin
Starlark struct {
Enabled bool `envconfig:"DRONE_STARLARK_ENABLED"`
StepLimit uint64 `envconfig:"DRONE_STARLARK_STEP_LIMIT"`
SizeLimit uint64 `envconfig:"DRONE_STARLARK_SIZE_LIMIT" default:"0"`
}
// License provides license configuration
License struct {
Key string `envconfig:"DRONE_LICENSE"`
Endpoint string `envconfig:"DRONE_LICENSE_ENDPOINT"`
}
// Logging provides the logging configuration.
Logging struct {
Debug bool `envconfig:"DRONE_LOGS_DEBUG"`
Trace bool `envconfig:"DRONE_LOGS_TRACE"`
Color bool `envconfig:"DRONE_LOGS_COLOR"`
Pretty bool `envconfig:"DRONE_LOGS_PRETTY"`
Text bool `envconfig:"DRONE_LOGS_TEXT"`
}
// Prometheus provides the prometheus configuration.
Prometheus struct {
EnableAnonymousAccess bool `envconfig:"DRONE_PROMETHEUS_ANONYMOUS_ACCESS" default:"false"`
}
// Redis provides the redis configuration.
Redis struct {
ConnectionString string `envconfig:"DRONE_REDIS_CONNECTION"`
Addr string `envconfig:"DRONE_REDIS_ADDR"`
Password string `envconfig:"DRONE_REDIS_PASSWORD"`
DB int `envconfig:"DRONE_REDIS_DB"`
}
// Repository provides the repository configuration.
Repository struct {
Filter []string `envconfig:"DRONE_REPOSITORY_FILTER"`
Visibility string `envconfig:"DRONE_REPOSITORY_VISIBILITY"`
Trusted bool `envconfig:"DRONE_REPOSITORY_TRUSTED"`
// THIS SETTING IS INTERNAL USE ONLY AND SHOULD
// NOT BE USED OR RELIED UPON IN PRODUCTION.
Ignore []string `envconfig:"DRONE_REPOSITORY_IGNORE"`
}
// Registries provides the registry configuration.
Registries struct {
Endpoint string `envconfig:"DRONE_REGISTRY_ENDPOINT"`
Password string `envconfig:"DRONE_REGISTRY_SECRET"`
SkipVerify bool `envconfig:"DRONE_REGISTRY_SKIP_VERIFY"`
}
// Secrets provides the secret configuration.
Secrets struct {
Endpoint string `envconfig:"DRONE_SECRET_ENDPOINT"`
Password string `envconfig:"DRONE_SECRET_SECRET"`
SkipVerify bool `envconfig:"DRONE_SECRET_SKIP_VERIFY"`
}
// RPC provides the rpc configuration.
RPC struct {
Server string `envconfig:"DRONE_RPC_SERVER"`
Secret string `envconfig:"DRONE_RPC_SECRET"`
Debug bool `envconfig:"DRONE_RPC_DEBUG"`
Host string `envconfig:"DRONE_RPC_HOST"`
Proto string `envconfig:"DRONE_RPC_PROTO"`
// Hosts map[string]string `envconfig:"DRONE_RPC_EXTRA_HOSTS"`
}
Agent struct {
Disabled bool `envconfig:"DRONE_AGENTS_DISABLED"`
}
// Runner provides the runner configuration.
Runner struct {
Local bool `envconfig:"DRONE_RUNNER_LOCAL"`
Image string `envconfig:"DRONE_RUNNER_IMAGE" default:"drone/controller:1"`
Platform string `envconfig:"DRONE_RUNNER_PLATFORM" default:"linux/amd64"`
OS string `envconfig:"DRONE_RUNNER_OS"`
Arch string `envconfig:"DRONE_RUNNER_ARCH"`
Kernel string `envconfig:"DRONE_RUNNER_KERNEL"`
Variant string `envconfig:"DRONE_RUNNER_VARIANT"`
Machine string `envconfig:"DRONE_RUNNER_NAME"`
Capacity int `envconfig:"DRONE_RUNNER_CAPACITY" default:"2"`
Labels map[string]string `envconfig:"DRONE_RUNNER_LABELS"`
Volumes []string `envconfig:"DRONE_RUNNER_VOLUMES"`
Networks []string `envconfig:"DRONE_RUNNER_NETWORKS"`
Devices []string `envconfig:"DRONE_RUNNER_DEVICES"`
Privileged []string `envconfig:"DRONE_RUNNER_PRIVILEGED_IMAGES"`
Environ map[string]string `envconfig:"DRONE_RUNNER_ENVIRON"`
Limits struct {
MemSwapLimit Bytes `envconfig:"DRONE_LIMIT_MEM_SWAP"`
MemLimit Bytes `envconfig:"DRONE_LIMIT_MEM"`
ShmSize Bytes `envconfig:"DRONE_LIMIT_SHM_SIZE"`
CPUQuota int64 `envconfig:"DRONE_LIMIT_CPU_QUOTA"`
CPUShares int64 `envconfig:"DRONE_LIMIT_CPU_SHARES"`
CPUSet string `envconfig:"DRONE_LIMIT_CPU_SET"`
}
}
// Server provides the server configuration.
Server struct {
Addr string `envconfig:"-"`
Host string `envconfig:"DRONE_SERVER_HOST" default:"localhost:8080"`
Port string `envconfig:"DRONE_SERVER_PORT" default:":8080"`
Proto string `envconfig:"DRONE_SERVER_PROTO" default:"http"`
Pprof bool `envconfig:"DRONE_PPROF_ENABLED"`
Acme bool `envconfig:"DRONE_TLS_AUTOCERT"`
Email string `envconfig:"DRONE_TLS_EMAIL"`
Cert string `envconfig:"DRONE_TLS_CERT"`
Key string `envconfig:"DRONE_TLS_KEY"`
}
// Proxy provides proxy server configuration.
Proxy struct {
Addr string `envconfig:"-"`
Host string `envconfig:"DRONE_SERVER_PROXY_HOST"`
Proto string `envconfig:"DRONE_SERVER_PROXY_PROTO"`
}
// Registration configuration.
Registration struct {
Closed bool `envconfig:"DRONE_REGISTRATION_CLOSED"`
}
// Authentication Controller configuration
Authentication struct {
Endpoint string `envconfig:"DRONE_ADMISSION_PLUGIN_ENDPOINT"`
Secret string `envconfig:"DRONE_ADMISSION_PLUGIN_SECRET"`
SkipVerify bool `envconfig:"DRONE_ADMISSION_PLUGIN_SKIP_VERIFY"`
}
// Session provides the session configuration.
Session struct {
Timeout time.Duration `envconfig:"DRONE_COOKIE_TIMEOUT" default:"720h"`
Secret string `envconfig:"DRONE_COOKIE_SECRET"`
Secure bool `envconfig:"DRONE_COOKIE_SECURE"`
}
// Status provides status configurations.
Status struct {
Disabled bool `envconfig:"DRONE_STATUS_DISABLED"`
Name string `envconfig:"DRONE_STATUS_NAME"`
}
// Users provides the user configuration.
Users struct {
Create UserCreate `envconfig:"DRONE_USER_CREATE"`
Filter []string `envconfig:"DRONE_USER_FILTER"`
MinAge time.Duration `envconfig:"DRONE_MIN_AGE"`
}
// Webhook provides the webhook configuration.
Webhook struct {
Events []string `envconfig:"DRONE_WEBHOOK_EVENTS"`
Endpoint []string `envconfig:"DRONE_WEBHOOK_ENDPOINT"`
Secret string `envconfig:"DRONE_WEBHOOK_SECRET"`
SkipVerify bool `envconfig:"DRONE_WEBHOOK_SKIP_VERIFY"`
}
// Yaml provides the yaml webhook configuration.
Yaml struct {
Endpoint string `envconfig:"DRONE_YAML_ENDPOINT"`
Secret string `envconfig:"DRONE_YAML_SECRET"`
SkipVerify bool `envconfig:"DRONE_YAML_SKIP_VERIFY"`
Timeout time.Duration `envconfig:"DRONE_YAML_TIMEOUT" default:"1m"`
}
// Convert provides the converter webhook configuration.
Convert struct {
Extension string `envconfig:"DRONE_CONVERT_PLUGIN_EXTENSION"`
Endpoint string `envconfig:"DRONE_CONVERT_PLUGIN_ENDPOINT"`
Secret string `envconfig:"DRONE_CONVERT_PLUGIN_SECRET"`
SkipVerify bool `envconfig:"DRONE_CONVERT_PLUGIN_SKIP_VERIFY"`
CacheSize int `envconfig:"DRONE_CONVERT_PLUGIN_CACHE_SIZE" default:"10"`
Timeout time.Duration `envconfig:"DRONE_CONVERT_TIMEOUT" default:"1m"`
// this flag can be removed once we solve for
// https://github.com/harness/drone/pull/2994#issuecomment-795955312
Multi bool `envconfig:"DRONE_CONVERT_MULTI"`
}
// Validate provides the validation webhook configuration.
Validate struct {
Endpoint string `envconfig:"DRONE_VALIDATE_PLUGIN_ENDPOINT"`
Secret string `envconfig:"DRONE_VALIDATE_PLUGIN_SECRET"`
SkipVerify bool `envconfig:"DRONE_VALIDATE_PLUGIN_SKIP_VERIFY"`
Timeout time.Duration `envconfig:"DRONE_VALIDATE_TIMEOUT" default:"1m"`
}
//
// Source code management.
//
// Bitbucket provides the bitbucket client configuration.
Bitbucket struct {
ClientID string `envconfig:"DRONE_BITBUCKET_CLIENT_ID"`
ClientSecret string `envconfig:"DRONE_BITBUCKET_CLIENT_SECRET"`
SkipVerify bool `envconfig:"DRONE_BITBUCKET_SKIP_VERIFY"`
Debug bool `envconfig:"DRONE_BITBUCKET_DEBUG"`
}
// Gitea provides the gitea client configuration.
Gitea struct {
Server string `envconfig:"DRONE_GITEA_SERVER"`
ClientID string `envconfig:"DRONE_GITEA_CLIENT_ID"`
ClientSecret string `envconfig:"DRONE_GITEA_CLIENT_SECRET"`
RedirectURL string `envconfig:"DRONE_GITEA_REDIRECT_URL"`
SkipVerify bool `envconfig:"DRONE_GITEA_SKIP_VERIFY"`
Scope []string `envconfig:"DRONE_GITEA_SCOPE" default:"repo,repo:status,user:email,read:org"`
Debug bool `envconfig:"DRONE_GITEA_DEBUG"`
}
// Github provides the github client configuration.
Github struct {
Server string `envconfig:"DRONE_GITHUB_SERVER" default:"https://github.com"`
APIServer string `envconfig:"DRONE_GITHUB_API_SERVER"`
ClientID string `envconfig:"DRONE_GITHUB_CLIENT_ID"`
ClientSecret string `envconfig:"DRONE_GITHUB_CLIENT_SECRET"`
SkipVerify bool `envconfig:"DRONE_GITHUB_SKIP_VERIFY"`
Scope []string `envconfig:"DRONE_GITHUB_SCOPE" default:"repo,repo:status,user:email,read:org"`
RateLimit int `envconfig:"DRONE_GITHUB_USER_RATELIMIT"`
Debug bool `envconfig:"DRONE_GITHUB_DEBUG"`
}
// Gitee providers the gitee client configuration.
Gitee struct {
Server string `envconfig:"DRONE_GITEE_SERVER" default:"https://gitee.com"`
APIServer string `envconfig:"DRONE_GITEE_API_SERVER" default:"https://gitee.com/api/v5"`
ClientID string `envconfig:"DRONE_GITEE_CLIENT_ID"`
ClientSecret string `envconfig:"DRONE_GITEE_CLIENT_SECRET"`
RedirectURL string `envconfig:"DRONE_GITEE_REDIRECT_URL"`
SkipVerify bool `envconfig:"DRONE_GITEE_SKIP_VERIFY"`
Scope []string `envconfig:"DRONE_GITEE_SCOPE" default:"user_info,projects,pull_requests,hook"`
Debug bool `envconfig:"DRONE_GITEE_DEBUG"`
}
// GitLab provides the gitlab client configuration.
GitLab struct {
Server string `envconfig:"DRONE_GITLAB_SERVER" default:"https://gitlab.com"`
ClientID string `envconfig:"DRONE_GITLAB_CLIENT_ID"`
ClientSecret string `envconfig:"DRONE_GITLAB_CLIENT_SECRET"`
SkipVerify bool `envconfig:"DRONE_GITLAB_SKIP_VERIFY"`
Debug bool `envconfig:"DRONE_GITLAB_DEBUG"`
}
// Gogs provides the gogs client configuration.
Gogs struct {
Server string `envconfig:"DRONE_GOGS_SERVER"`
SkipVerify bool `envconfig:"DRONE_GOGS_SKIP_VERIFY"`
Debug bool `envconfig:"DRONE_GOGS_DEBUG"`
}
// Stash provides the stash client configuration.
Stash struct {
Server string `envconfig:"DRONE_STASH_SERVER"`
ConsumerKey string `envconfig:"DRONE_STASH_CONSUMER_KEY"`
ConsumerSecret string `envconfig:"DRONE_STASH_CONSUMER_SECRET"`
PrivateKey string `envconfig:"DRONE_STASH_PRIVATE_KEY"`
SkipVerify bool `envconfig:"DRONE_STASH_SKIP_VERIFY"`
Debug bool `envconfig:"DRONE_STASH_DEBUG"`
}
// S3 provides the storage configuration.
S3 struct {
Bucket string `envconfig:"DRONE_S3_BUCKET"`
Prefix string `envconfig:"DRONE_S3_PREFIX"`
Endpoint string `envconfig:"DRONE_S3_ENDPOINT"`
PathStyle bool `envconfig:"DRONE_S3_PATH_STYLE"`
}
//AzureBlob providers the storage configuration.
AzureBlob struct {
ContainerName string `envconfig:"DRONE_AZURE_BLOB_CONTAINER_NAME"`
StorageAccountName string `envconfig:"DRONE_AZURE_STORAGE_ACCOUNT_NAME"`
StorageAccessKey string `envconfig:"DRONE_AZURE_STORAGE_ACCESS_KEY"`
}
// HTTP provides http configuration.
HTTP struct {
AllowedHosts []string `envconfig:"DRONE_HTTP_ALLOWED_HOSTS"`
HostsProxyHeaders []string `envconfig:"DRONE_HTTP_PROXY_HEADERS"`
SSLRedirect bool `envconfig:"DRONE_HTTP_SSL_REDIRECT"`
SSLTemporaryRedirect bool `envconfig:"DRONE_HTTP_SSL_TEMPORARY_REDIRECT"`
SSLHost string `envconfig:"DRONE_HTTP_SSL_HOST"`
SSLProxyHeaders map[string]string `envconfig:"DRONE_HTTP_SSL_PROXY_HEADERS"`
STSSeconds int64 `envconfig:"DRONE_HTTP_STS_SECONDS"`
STSIncludeSubdomains bool `envconfig:"DRONE_HTTP_STS_INCLUDE_SUBDOMAINS"`
STSPreload bool `envconfig:"DRONE_HTTP_STS_PRELOAD"`
ForceSTSHeader bool `envconfig:"DRONE_HTTP_STS_FORCE_HEADER"`
BrowserXSSFilter bool `envconfig:"DRONE_HTTP_BROWSER_XSS_FILTER" default:"true"`
FrameDeny bool `envconfig:"DRONE_HTTP_FRAME_DENY" default:"true"`
ContentTypeNosniff bool `envconfig:"DRONE_HTTP_CONTENT_TYPE_NO_SNIFF"`
ContentSecurityPolicy string `envconfig:"DRONE_HTTP_CONTENT_SECURITY_POLICY"`
ReferrerPolicy string `envconfig:"DRONE_HTTP_REFERRER_POLICY"`
}
)
// Environ returns the settings from the environment.
func Environ() (Config, error) {
cfg := Config{}
err := envconfig.Process("", &cfg)
defaultAddress(&cfg)
defaultProxy(&cfg)
defaultRunner(&cfg)
defaultSession(&cfg)
defaultCallback(&cfg)
configureGithub(&cfg)
if err := kubernetesServiceConflict(&cfg); err != nil {
return cfg, err
}
return cfg, err
}
// String returns the configuration in string format.
func (c *Config) String() string {
out, _ := yaml.Marshal(c)
return string(out)
}
// IsGitHub returns true if the GitHub integration
// is activated.
func (c *Config) IsGitHub() bool {
return c.Github.ClientID != ""
}
// IsGitHubEnterprise returns true if the GitHub
// integration is activated.
func (c *Config) IsGitHubEnterprise() bool {
return c.IsGitHub() && !strings.HasPrefix(c.Github.Server, "https://github.com")
}
// IsGitLab returns true if the GitLab integration
// is activated.
func (c *Config) IsGitLab() bool {
return c.GitLab.ClientID != ""
}
// IsGogs returns true if the Gogs integration
// is activated.
func (c *Config) IsGogs() bool {
return c.Gogs.Server != ""
}
// IsGitea returns true if the Gitea integration
// is activated.
func (c *Config) IsGitea() bool {
return c.Gitea.Server != ""
}
// IsGitee returns true if the Gitee integration
// is activated.
func (c *Config) IsGitee() bool {
return c.Gitee.ClientID != ""
}
// IsBitbucket returns true if the Bitbucket Cloud
// integration is activated.
func (c *Config) IsBitbucket() bool {
return c.Bitbucket.ClientID != ""
}
// IsStash returns true if the Atlassian Stash
// integration is activated.
func (c *Config) IsStash() bool {
return c.Stash.Server != ""
}
func cleanHostname(hostname string) string {
hostname = strings.ToLower(hostname)
hostname = strings.TrimPrefix(hostname, "http://")
hostname = strings.TrimPrefix(hostname, "https://")
return hostname
}
func defaultAddress(c *Config) {
if c.Server.Key != "" || c.Server.Cert != "" || c.Server.Acme {
c.Server.Port = ":443"
c.Server.Proto = "https"
}
c.Server.Host = cleanHostname(c.Server.Host)
c.Server.Addr = c.Server.Proto + "://" + c.Server.Host
}
func defaultProxy(c *Config) {
if c.Proxy.Host == "" {
c.Proxy.Host = c.Server.Host
} else {
c.Proxy.Host = cleanHostname(c.Proxy.Host)
}
if c.Proxy.Proto == "" {
c.Proxy.Proto = c.Server.Proto
}
c.Proxy.Addr = c.Proxy.Proto + "://" + c.Proxy.Host
}
func defaultCallback(c *Config) {
if c.RPC.Host == "" {
c.RPC.Host = c.Server.Host
}
if c.RPC.Proto == "" {
c.RPC.Proto = c.Server.Proto
}
}
func defaultRunner(c *Config) {
if c.Runner.Machine == "" {
c.Runner.Machine = hostname
}
parts := strings.Split(c.Runner.Platform, "/")
if len(parts) == 2 && c.Runner.OS == "" {
c.Runner.OS = parts[0]
}
if len(parts) == 2 && c.Runner.Arch == "" {
c.Runner.Arch = parts[1]
}
}
func defaultSession(c *Config) {
if c.Session.Secret == "" {
c.Session.Secret = uniuri.NewLen(32)
}
}
func configureGithub(c *Config) {
if c.Github.APIServer != "" {
return
}
if c.Github.Server == "https://github.com" {
c.Github.APIServer = "https://api.github.com"
} else {
c.Github.APIServer = strings.TrimSuffix(c.Github.Server, "/") + "/api/v3"
}
}
func kubernetesServiceConflict(c *Config) error {
if strings.HasPrefix(c.Server.Port, "tcp://") {
return errors.New("Invalid port configuration. See https://community.harness.io/t/drone-server-changing-ports-protocol/11400")
}
return nil
}
// Bytes stores number bytes (e.g. megabytes)
type Bytes int64
// Decode implements a decoder that parses a string representation
// of bytes into the number of bytes it represents.
func (b *Bytes) Decode(value string) error {
v, err := humanize.ParseBytes(value)
*b = Bytes(v)
return err
}
// Int64 returns the int64 value of the Byte.
func (b *Bytes) Int64() int64 {
return int64(*b)
}
// String returns the string value of the Byte.
func (b *Bytes) String() string {
return fmt.Sprint(*b)
}
// UserCreate stores account information used to bootstrap
// the admin user account when the system initializes.
type UserCreate struct {
Username string
Machine bool
Admin bool
Token string
}
// Decode implements a decoder that extracts user information
// from the environment variable string.
func (u *UserCreate) Decode(value string) error {
for _, param := range strings.Split(value, ",") {
parts := strings.Split(param, ":")
if len(parts) != 2 {
continue
}
key := parts[0]
val := parts[1]
switch key {
case "username":
u.Username = val
case "token":
u.Token = val
case "machine":
u.Machine = val == "true"
case "admin":
u.Admin = val == "true"
}
}
return nil
}

View File

@ -1,48 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import "testing"
func Test_cleanHostname(t *testing.T) {
tests := []struct {
name string
hostname string
want string
}{
{
name: "no prefix",
hostname: "drone.io",
want: "drone.io",
},
{
name: "http prefix",
hostname: "http://drone.io",
want: "drone.io",
},
{
name: "https prefix",
hostname: "https://drone.io",
want: "drone.io",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := cleanHostname(tt.hostname); got != tt.want {
t.Errorf("cleanHostname() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -1,286 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"net/http"
"net/http/httputil"
"strings"
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/go-scm/scm"
"github.com/drone/go-scm/scm/driver/bitbucket"
"github.com/drone/go-scm/scm/driver/gitea"
"github.com/drone/go-scm/scm/driver/gitee"
"github.com/drone/go-scm/scm/driver/github"
"github.com/drone/go-scm/scm/driver/gitlab"
"github.com/drone/go-scm/scm/driver/gogs"
"github.com/drone/go-scm/scm/driver/stash"
"github.com/drone/go-scm/scm/transport/oauth1"
"github.com/drone/go-scm/scm/transport/oauth2"
"github.com/google/wire"
"github.com/sirupsen/logrus"
)
// wire set for loading the scm client.
var clientSet = wire.NewSet(
provideClient,
)
// provideBitbucketClient is a Wire provider function that
// returns a Source Control Management client based on the
// environment configuration.
func provideClient(config config.Config) *scm.Client {
switch {
case config.Bitbucket.ClientID != "":
return provideBitbucketClient(config)
case config.Github.ClientID != "":
return provideGithubClient(config)
case config.Gitee.ClientID != "":
return provideGiteeClient(config)
case config.Gitea.Server != "":
return provideGiteaClient(config)
case config.GitLab.ClientID != "":
return provideGitlabClient(config)
case config.Gogs.Server != "":
return provideGogsClient(config)
case config.Stash.ConsumerKey != "":
return provideStashClient(config)
}
logrus.Fatalln("main: source code management system not configured")
return nil
}
// provideBitbucketClient is a Wire provider function that
// returns a Bitbucket Cloud client based on the environment
// configuration.
func provideBitbucketClient(config config.Config) *scm.Client {
client := bitbucket.NewDefault()
client.Client = &http.Client{
Transport: &oauth2.Transport{
Source: &oauth2.Refresher{
ClientID: config.Bitbucket.ClientID,
ClientSecret: config.Bitbucket.ClientSecret,
Endpoint: "https://bitbucket.org/site/oauth2/access_token",
Source: oauth2.ContextTokenSource(),
},
},
}
if config.Bitbucket.Debug {
client.DumpResponse = httputil.DumpResponse
}
return client
}
// provideGithubClient is a Wire provider function that returns
// a GitHub client based on the environment configuration.
func provideGithubClient(config config.Config) *scm.Client {
client, err := github.New(config.Github.APIServer)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the GitHub client")
}
if config.Github.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth2.Transport{
Source: oauth2.ContextTokenSource(),
Base: defaultTransport(config.Github.SkipVerify),
},
}
return client
}
// provideGiteeClient is a Wire provider function that returns
// a Gitee client based on the environment configuration.
func provideGiteeClient(config config.Config) *scm.Client {
client, err := gitee.New(config.Gitee.APIServer)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the Gitee client")
}
if config.Gitee.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth2.Transport{
Scheme: oauth2.SchemeBearer,
Source: &oauth2.Refresher{
ClientID: config.Gitee.ClientID,
ClientSecret: config.Gitee.ClientSecret,
Endpoint: strings.TrimSuffix(config.Gitee.Server, "/") + "/oauth/token",
Source: oauth2.ContextTokenSource(),
},
Base: defaultTransport(config.Gitee.SkipVerify),
},
}
return client
}
// provideGiteaClient is a Wire provider function that returns
// a Gitea client based on the environment configuration.
func provideGiteaClient(config config.Config) *scm.Client {
client, err := gitea.New(config.Gitea.Server)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the Gitea client")
}
if config.Gitea.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth2.Transport{
Scheme: oauth2.SchemeBearer,
Source: &oauth2.Refresher{
ClientID: config.Gitea.ClientID,
ClientSecret: config.Gitea.ClientSecret,
Endpoint: strings.TrimSuffix(config.Gitea.Server, "/") + "/login/oauth/access_token",
Source: oauth2.ContextTokenSource(),
},
Base: defaultTransport(config.Gitea.SkipVerify),
},
}
return client
}
// provideGitlabClient is a Wire provider function that returns
// a GitLab client based on the environment configuration.
func provideGitlabClient(config config.Config) *scm.Client {
logrus.WithField("server", config.GitLab.Server).
WithField("client", config.GitLab.ClientID).
WithField("skip_verify", config.GitLab.SkipVerify).
Debugln("main: creating the GitLab client")
client, err := gitlab.New(config.GitLab.Server)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the GitLab client")
}
if config.GitLab.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth2.Transport{
Scheme: oauth2.SchemeBearer,
Source: &oauth2.Refresher{
ClientID: config.GitLab.ClientID,
ClientSecret: config.GitLab.ClientSecret,
Endpoint: strings.TrimSuffix(config.GitLab.Server, "/") + "/oauth/token",
Source: oauth2.ContextTokenSource(),
},
Base: defaultTransport(config.GitLab.SkipVerify),
},
}
return client
}
// provideGogsClient is a Wire provider function that returns
// a Gogs client based on the environment configuration.
func provideGogsClient(config config.Config) *scm.Client {
logrus.WithField("server", config.Gogs.Server).
WithField("skip_verify", config.Gogs.SkipVerify).
Debugln("main: creating the Gogs client")
client, err := gogs.New(config.Gogs.Server)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the Gogs client")
}
if config.Gogs.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth2.Transport{
Scheme: oauth2.SchemeToken,
Source: oauth2.ContextTokenSource(),
Base: defaultTransport(config.Gogs.SkipVerify),
},
}
return client
}
// provideStashClient is a Wire provider function that returns
// a Stash client based on the environment configuration.
func provideStashClient(config config.Config) *scm.Client {
logrus.WithField("server", config.Stash.Server).
WithField("skip_verify", config.Stash.SkipVerify).
Debugln("main: creating the Stash client")
privateKey, err := parsePrivateKeyFile(config.Stash.PrivateKey)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot parse the Stash Private Key")
}
client, err := stash.New(config.Stash.Server)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot create the Stash client")
}
if config.Stash.Debug {
client.DumpResponse = httputil.DumpResponse
}
client.Client = &http.Client{
Transport: &oauth1.Transport{
ConsumerKey: config.Stash.ConsumerKey,
PrivateKey: privateKey,
Source: oauth1.ContextTokenSource(),
Base: defaultTransport(config.Stash.SkipVerify),
},
}
return client
}
// defaultClient provides a default http.Client. If skipverify
// is true, the default transport will skip ssl verification.
func defaultClient(skipverify bool) *http.Client {
client := &http.Client{}
client.Transport = defaultTransport(skipverify)
return client
}
// defaultTransport provides a default http.Transport. If
// skipverify is true, the transport will skip ssl verification.
func defaultTransport(skipverify bool) http.RoundTripper {
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: skipverify,
},
}
}
// parsePrivateKeyFile is a helper function that parses an
// RSA Private Key file encoded in PEM format.
func parsePrivateKeyFile(path string) (*rsa.PrivateKey, error) {
d, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return parsePrivateKey(d)
}
// parsePrivateKey is a helper function that parses an RSA
// Private Key encoded in PEM format.
func parsePrivateKey(data []byte) (*rsa.PrivateKey, error) {
p, _ := pem.Decode(data)
return x509.ParsePKCS1PrivateKey(p.Bytes)
}

View File

@ -1,31 +0,0 @@
// Copyright 2021 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/service/redisdb"
"github.com/google/wire"
)
// wire set for loading the external services.
var externalSet = wire.NewSet(
provideRedisClient,
)
func provideRedisClient(config config.Config) (rdb redisdb.RedisDB, err error) {
return redisdb.New(config)
}

View File

@ -1,53 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/service/license"
"github.com/drone/go-scm/scm"
"github.com/google/wire"
"github.com/sirupsen/logrus"
)
// wire set for loading the license.
var licenseSet = wire.NewSet(
provideLicense,
license.NewService,
)
// provideLicense is a Wire provider function that returns a
// license loaded from a license file.
func provideLicense(client *scm.Client, config config.Config) *core.License {
l, err := license.Load(config.License)
if config.License == "" {
l = license.Trial(client.Driver.String())
} else if err != nil {
logrus.WithError(err).
Fatalln("main: invalid or expired license")
}
logrus.WithFields(
logrus.Fields{
"kind": l.Kind,
"expires": l.Expires,
"repo.limit": l.Repos,
"user.limit": l.Users,
"build.limit": l.Builds,
},
).Debugln("main: license loaded")
return l
}

View File

@ -1,223 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/go-login/login"
"github.com/drone/go-login/login/bitbucket"
"github.com/drone/go-login/login/gitea"
"github.com/drone/go-login/login/gitee"
"github.com/drone/go-login/login/github"
"github.com/drone/go-login/login/gitlab"
"github.com/drone/go-login/login/gogs"
"github.com/drone/go-login/login/stash"
"github.com/drone/go-scm/scm/transport/oauth2"
"strings"
"github.com/google/wire"
"github.com/sirupsen/logrus"
)
// wire set for loading the authenticator.
var loginSet = wire.NewSet(
provideLogin,
provideRefresher,
)
// provideLogin is a Wire provider function that returns an
// authenticator based on the environment configuration.
func provideLogin(config config.Config) login.Middleware {
switch {
case config.Bitbucket.ClientID != "":
return provideBitbucketLogin(config)
case config.Github.ClientID != "":
return provideGithubLogin(config)
case config.Gitee.ClientID != "":
return provideGiteeLogin(config)
case config.Gitea.Server != "":
return provideGiteaLogin(config)
case config.GitLab.ClientID != "":
return provideGitlabLogin(config)
case config.Gogs.Server != "":
return provideGogsLogin(config)
case config.Stash.ConsumerKey != "":
return provideStashLogin(config)
}
logrus.Fatalln("main: source code management system not configured")
return nil
}
// provideBitbucketLogin is a Wire provider function that
// returns a Bitbucket Cloud authenticator based on the
// environment configuration.
func provideBitbucketLogin(config config.Config) login.Middleware {
if config.Bitbucket.ClientID == "" {
return nil
}
return &bitbucket.Config{
ClientID: config.Bitbucket.ClientID,
ClientSecret: config.Bitbucket.ClientSecret,
RedirectURL: config.Server.Addr + "/login",
}
}
// provideGithubLogin is a Wire provider function that returns
// a GitHub authenticator based on the environment configuration.
func provideGithubLogin(config config.Config) login.Middleware {
if config.Github.ClientID == "" {
return nil
}
return &github.Config{
ClientID: config.Github.ClientID,
ClientSecret: config.Github.ClientSecret,
Scope: config.Github.Scope,
Server: config.Github.Server,
Client: defaultClient(config.Github.SkipVerify),
Logger: logrus.StandardLogger(),
}
}
// provideGiteeLogin is a Wire provider function that returns
// a Gitee authenticator based on the environment configuration.
func provideGiteeLogin(config config.Config) login.Middleware {
if config.Gitee.ClientID == "" {
return nil
}
redirectURL := config.Gitee.RedirectURL
if redirectURL == "" {
redirectURL = config.Server.Addr + "/login"
}
return &gitee.Config{
ClientID: config.Gitee.ClientID,
ClientSecret: config.Gitee.ClientSecret,
RedirectURL: redirectURL,
Server: config.Gitee.Server,
Scope: config.Gitee.Scope,
Client: defaultClient(config.Gitee.SkipVerify),
}
}
// provideGiteaLogin is a Wire provider function that returns
// a Gitea authenticator based on the environment configuration.
func provideGiteaLogin(config config.Config) login.Middleware {
if config.Gitea.Server == "" {
return nil
}
redirectURL := config.Gitea.RedirectURL
if redirectURL == "" {
redirectURL = config.Server.Addr + "/login"
}
return &gitea.Config{
ClientID: config.Gitea.ClientID,
ClientSecret: config.Gitea.ClientSecret,
Server: config.Gitea.Server,
Client: defaultClient(config.Gitea.SkipVerify),
Logger: logrus.StandardLogger(),
RedirectURL: redirectURL,
Scope: config.Gitea.Scope,
}
}
// provideGitlabLogin is a Wire provider function that returns
// a GitLab authenticator based on the environment configuration.
func provideGitlabLogin(config config.Config) login.Middleware {
if config.GitLab.ClientID == "" {
return nil
}
return &gitlab.Config{
ClientID: config.GitLab.ClientID,
ClientSecret: config.GitLab.ClientSecret,
RedirectURL: config.Server.Addr + "/login",
Server: config.GitLab.Server,
Client: defaultClient(config.GitLab.SkipVerify),
}
}
// provideGogsLogin is a Wire provider function that returns
// a Gogs authenticator based on the environment configuration.
func provideGogsLogin(config config.Config) login.Middleware {
if config.Gogs.Server == "" {
return nil
}
return &gogs.Config{
Label: "drone",
Login: "/login/form",
Server: config.Gogs.Server,
Client: defaultClient(config.Gogs.SkipVerify),
}
}
// provideStashLogin is a Wire provider function that returns
// a Stash authenticator based on the environment configuration.
func provideStashLogin(config config.Config) login.Middleware {
if config.Stash.ConsumerKey == "" {
return nil
}
privateKey, err := stash.ParsePrivateKeyFile(config.Stash.PrivateKey)
if err != nil {
logrus.WithError(err).
Fatalln("main: cannot parse Private Key file")
}
return &stash.Config{
Address: config.Stash.Server,
ConsumerKey: config.Stash.ConsumerKey,
ConsumerSecret: config.Stash.ConsumerSecret,
PrivateKey: privateKey,
CallbackURL: config.Server.Addr + "/login",
Client: defaultClient(config.Stash.SkipVerify),
}
}
// provideRefresher is a Wire provider function that returns
// an oauth token refresher for Bitbucket and Gitea
func provideRefresher(config config.Config) *oauth2.Refresher {
switch {
case config.Bitbucket.ClientID != "":
return &oauth2.Refresher{
ClientID: config.Bitbucket.ClientID,
ClientSecret: config.Bitbucket.ClientSecret,
Endpoint: "https://bitbucket.org/site/oauth2/access_token",
Source: oauth2.ContextTokenSource(),
Client: defaultClient(config.Bitbucket.SkipVerify),
}
case config.Gitea.ClientID != "":
return &oauth2.Refresher{
ClientID: config.Gitea.ClientID,
ClientSecret: config.Gitea.ClientSecret,
Endpoint: strings.TrimSuffix(config.Gitea.Server, "/") + "/login/oauth/access_token",
Source: oauth2.ContextTokenSource(),
Client: defaultClient(config.Gitea.SkipVerify),
}
case config.GitLab.ClientID != "":
return &oauth2.Refresher{
ClientID: config.GitLab.ClientID,
ClientSecret: config.GitLab.ClientSecret,
Endpoint: strings.TrimSuffix(config.GitLab.Server, "/") + "/oauth/token",
Source: oauth2.ContextTokenSource(),
Client: defaultClient(config.GitLab.SkipVerify),
}
case config.Gitee.ClientID != "":
return &oauth2.Refresher{
ClientID: config.Gitee.ClientID,
ClientSecret: config.Gitee.ClientSecret,
Endpoint: strings.TrimSuffix(config.Gitee.Server, "/") + "/oauth/token",
Source: oauth2.ContextTokenSource(),
Client: defaultClient(config.Gitee.SkipVerify),
}
}
return nil
}

View File

@ -1,171 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
spec "github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/plugin/admission"
"github.com/drone/drone/plugin/config"
"github.com/drone/drone/plugin/converter"
"github.com/drone/drone/plugin/registry"
"github.com/drone/drone/plugin/secret"
"github.com/drone/drone/plugin/validator"
"github.com/drone/drone/plugin/webhook"
"github.com/drone/go-scm/scm"
"github.com/google/wire"
)
// wire set for loading plugins.
var pluginSet = wire.NewSet(
provideAdmissionPlugin,
provideConfigPlugin,
provideConvertPlugin,
provideRegistryPlugin,
provideSecretPlugin,
provideValidatePlugin,
provideWebhookPlugin,
)
// provideAdmissionPlugin is a Wire provider function that
// returns an admission plugin based on the environment
// configuration.
func provideAdmissionPlugin(client *scm.Client, orgs core.OrganizationService, users core.UserService, config spec.Config) core.AdmissionService {
return admission.Combine(
admission.Membership(orgs, config.Users.Filter),
admission.Open(config.Registration.Closed),
admission.Nobot(users, config.Users.MinAge),
admission.External(
config.Authn.Endpoint,
config.Authn.Secret,
config.Authn.SkipVerify,
),
)
}
// provideConfigPlugin is a Wire provider function that returns
// a yaml configuration plugin based on the environment
// configuration.
func provideConfigPlugin(client *scm.Client, contents core.FileService, conf spec.Config) core.ConfigService {
return config.Combine(
config.Memoize(
config.Global(
conf.Yaml.Endpoint,
conf.Yaml.Secret,
conf.Yaml.SkipVerify,
conf.Yaml.Timeout,
),
),
config.Repository(contents),
)
}
// provideConvertPlugin is a Wire provider function that returns
// a yaml conversion plugin based on the environment
// configuration.
func provideConvertPlugin(client *scm.Client, fileService core.FileService, conf spec.Config, templateStore core.TemplateStore) core.ConvertService {
return converter.Combine(
conf.Convert.Multi,
converter.Legacy(false),
converter.Starlark(
conf.Starlark.Enabled,
conf.Starlark.StepLimit,
conf.Starlark.SizeLimit,
),
converter.Jsonnet(
conf.Jsonnet.Enabled,
conf.Jsonnet.ImportLimit,
fileService,
),
converter.Template(
templateStore,
conf.Starlark.StepLimit,
conf.Starlark.SizeLimit,
),
converter.Memoize(
converter.Remote(
conf.Convert.Endpoint,
conf.Convert.Secret,
conf.Convert.Extension,
conf.Convert.SkipVerify,
conf.Convert.Timeout,
),
conf.Convert.CacheSize,
),
)
}
// provideRegistryPlugin is a Wire provider function that
// returns a registry plugin based on the environment
// configuration.
func provideRegistryPlugin(config spec.Config) core.RegistryService {
return registry.Combine(
registry.External(
config.Secrets.Endpoint,
config.Secrets.Password,
config.Secrets.SkipVerify,
),
registry.FileSource(
config.Docker.Config,
),
registry.EndpointSource(
config.Registries.Endpoint,
config.Registries.Password,
config.Registries.SkipVerify,
),
)
}
// provideSecretPlugin is a Wire provider function that returns
// a secret plugin based on the environment configuration.
func provideSecretPlugin(config spec.Config) core.SecretService {
return secret.External(
config.Secrets.Endpoint,
config.Secrets.Password,
config.Secrets.SkipVerify,
)
}
// provideValidatePlugin is a Wire provider function that
// returns a yaml validation plugin based on the environment
// configuration.
func provideValidatePlugin(conf spec.Config) core.ValidateService {
return validator.Combine(
validator.Remote(
conf.Validate.Endpoint,
conf.Validate.Secret,
conf.Validate.SkipVerify,
conf.Validate.Timeout,
),
// THIS FEATURE IS INTERNAL USE ONLY AND SHOULD
// NOT BE USED OR RELIED UPON IN PRODUCTION.
validator.Filter(
nil,
conf.Repository.Ignore,
),
)
}
// provideWebhookPlugin is a Wire provider function that returns
// a webhook plugin based on the environment configuration.
func provideWebhookPlugin(config spec.Config, system *core.System) core.WebhookSender {
return webhook.New(webhook.Config{
Events: config.Webhook.Events,
Endpoint: config.Webhook.Endpoint,
Secret: config.Webhook.Secret,
System: system,
})
}

View File

@ -1,78 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone-runtime/engine/docker"
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/operator/manager"
"github.com/drone/drone/operator/runner"
"github.com/google/wire"
"github.com/sirupsen/logrus"
)
// wire set for loading the server.
var runnerSet = wire.NewSet(
provideRunner,
)
// provideRunner is a Wire provider function that returns a
// local build runner configured from the environment.
func provideRunner(
manager manager.BuildManager,
secrets core.SecretService,
registry core.RegistryService,
config config.Config,
) *runner.Runner {
// the local runner is only created when remote agents
// are disabled
if config.Agent.Disabled == false {
return nil
}
engine, err := docker.NewEnv()
if err != nil {
logrus.WithError(err).
Fatalln("cannot load the docker engine")
return nil
}
return &runner.Runner{
Platform: config.Runner.Platform,
OS: config.Runner.OS,
Arch: config.Runner.Arch,
Kernel: config.Runner.Kernel,
Variant: config.Runner.Variant,
Engine: engine,
Manager: manager,
Secrets: secrets,
Registry: registry,
Volumes: config.Runner.Volumes,
Networks: config.Runner.Networks,
Devices: config.Runner.Devices,
Privileged: config.Runner.Privileged,
Machine: config.Runner.Machine,
Labels: config.Runner.Labels,
Environ: config.Runner.Environ,
Limits: runner.Limits{
MemSwapLimit: int64(config.Runner.Limits.MemSwapLimit),
MemLimit: int64(config.Runner.Limits.MemLimit),
ShmSize: int64(config.Runner.Limits.ShmSize),
CPUQuota: config.Runner.Limits.CPUQuota,
CPUShares: config.Runner.Limits.CPUShares,
CPUSet: config.Runner.Limits.CPUSet,
},
}
}

View File

@ -1,34 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone/core"
"github.com/drone/drone/scheduler/queue"
"github.com/drone/drone/service/redisdb"
"github.com/google/wire"
)
// wire set for loading the scheduler.
var schedulerSet = wire.NewSet(
provideScheduler,
)
// provideScheduler is a Wire provider function that returns a
// scheduler based on the environment configuration.
func provideScheduler(store core.StageStore, r redisdb.RedisDB) core.Scheduler {
return queue.New(store, r)
}

View File

@ -1,147 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"net/http"
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/handler/api"
"github.com/drone/drone/handler/health"
"github.com/drone/drone/handler/web"
"github.com/drone/drone/metric"
"github.com/drone/drone/operator/manager"
"github.com/drone/drone/operator/manager/rpc"
"github.com/drone/drone/operator/manager/rpc2"
"github.com/drone/drone/server"
"github.com/google/wire"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/unrolled/secure"
)
type (
healthzHandler http.Handler
metricsHandler http.Handler
pprofHandler http.Handler
rpcHandlerV1 http.Handler
rpcHandlerV2 http.Handler
)
// wire set for loading the server.
var serverSet = wire.NewSet(
manager.New,
api.New,
web.New,
provideHealthz,
provideMetric,
providePprof,
provideRouter,
provideRPC,
provideRPC2,
provideServer,
provideServerOptions,
)
// provideRouter is a Wire provider function that returns a
// router that is serves the provided handlers.
func provideRouter(api api.Server, web web.Server, rpcv1 rpcHandlerV1, rpcv2 rpcHandlerV2, healthz healthzHandler, metrics *metric.Server, pprof pprofHandler) *chi.Mux {
r := chi.NewRouter()
r.Mount("/healthz", healthz)
r.Mount("/metrics", metrics)
r.Mount("/api", api.Handler())
r.Mount("/rpc/v2", rpcv2)
r.Mount("/rpc", rpcv1)
r.Mount("/", web.Handler())
r.Mount("/debug", pprof)
return r
}
// provideMetric is a Wire provider function that returns the
// healthcheck server.
func provideHealthz() healthzHandler {
v := health.New()
return healthzHandler(v)
}
// provideMetric is a Wire provider function that returns the
// metrics server exposing metrics in prometheus format.
func provideMetric(session core.Session, config config.Config) *metric.Server {
return metric.NewServer(session, config.Prometheus.EnableAnonymousAccess)
}
// providePprof is a Wire provider function that returns the
// pprof server endpoints.
func providePprof(config config.Config) pprofHandler {
if config.Server.Pprof == false {
return pprofHandler(
http.NotFoundHandler(),
)
}
return pprofHandler(
middleware.Profiler(),
)
}
// provideRPC is a Wire provider function that returns an rpc
// handler that exposes the build manager to a remote agent.
func provideRPC(m manager.BuildManager, config config.Config) rpcHandlerV1 {
v := rpc.NewServer(m, config.RPC.Secret)
return rpcHandlerV1(v)
}
// provideRPC2 is a Wire provider function that returns an rpc
// handler that exposes the build manager to a remote agent.
func provideRPC2(m manager.BuildManager, config config.Config) rpcHandlerV2 {
v := rpc2.NewServer(m, config.RPC.Secret)
return rpcHandlerV2(v)
}
// provideServer is a Wire provider function that returns an
// http server that is configured from the environment.
func provideServer(handler *chi.Mux, config config.Config) *server.Server {
return &server.Server{
Acme: config.Server.Acme,
Addr: config.Server.Port,
Cert: config.Server.Cert,
Key: config.Server.Key,
Host: config.Server.Host,
Handler: handler,
}
}
// provideServerOptions is a Wire provider function that returns
// the http web server security option from the environment.
func provideServerOptions(config config.Config) secure.Options {
return secure.Options{
AllowedHosts: config.HTTP.AllowedHosts,
HostsProxyHeaders: config.HTTP.HostsProxyHeaders,
SSLRedirect: config.HTTP.SSLRedirect,
SSLTemporaryRedirect: config.HTTP.SSLTemporaryRedirect,
SSLHost: config.HTTP.SSLHost,
SSLProxyHeaders: config.HTTP.SSLProxyHeaders,
STSSeconds: config.HTTP.STSSeconds,
STSIncludeSubdomains: config.HTTP.STSIncludeSubdomains,
STSPreload: config.HTTP.STSPreload,
ForceSTSHeader: config.HTTP.ForceSTSHeader,
FrameDeny: config.HTTP.FrameDeny,
ContentTypeNosniff: config.HTTP.ContentTypeNosniff,
BrowserXssFilter: config.HTTP.BrowserXSSFilter,
ContentSecurityPolicy: config.HTTP.ContentSecurityPolicy,
ReferrerPolicy: config.HTTP.ReferrerPolicy,
}
}

View File

@ -1,220 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"time"
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/livelog"
"github.com/drone/drone/metric/sink"
"github.com/drone/drone/pubsub"
"github.com/drone/drone/service/canceler"
"github.com/drone/drone/service/canceler/reaper"
"github.com/drone/drone/service/commit"
contents "github.com/drone/drone/service/content"
"github.com/drone/drone/service/content/cache"
"github.com/drone/drone/service/hook"
"github.com/drone/drone/service/hook/parser"
"github.com/drone/drone/service/linker"
"github.com/drone/drone/service/netrc"
orgs "github.com/drone/drone/service/org"
"github.com/drone/drone/service/repo"
"github.com/drone/drone/service/status"
"github.com/drone/drone/service/syncer"
"github.com/drone/drone/service/token"
"github.com/drone/drone/service/transfer"
"github.com/drone/drone/service/user"
"github.com/drone/drone/session"
"github.com/drone/drone/trigger"
"github.com/drone/drone/trigger/cron"
"github.com/drone/drone/version"
"github.com/drone/go-scm/scm"
"github.com/google/wire"
)
// wire set for loading the services.
var serviceSet = wire.NewSet(
canceler.New,
commit.New,
cron.New,
livelog.New,
linker.New,
parser.New,
pubsub.New,
token.Renewer,
transfer.New,
trigger.New,
user.New,
provideRepositoryService,
provideContentService,
provideDatadog,
provideHookService,
provideNetrcService,
provideOrgService,
provideReaper,
provideSession,
provideStatusService,
provideSyncer,
provideSystem,
)
// provideContentService is a Wire provider function that
// returns a contents service wrapped with a simple LRU cache.
func provideContentService(client *scm.Client, renewer core.Renewer) core.FileService {
return cache.Contents(
contents.New(client, renewer),
)
}
// provideHookService is a Wire provider function that returns a
// hook service based on the environment configuration.
func provideHookService(client *scm.Client, renewer core.Renewer, config config.Config) core.HookService {
return hook.New(client, config.Proxy.Addr, renewer)
}
// provideNetrcService is a Wire provider function that returns
// a netrc service based on the environment configuration.
func provideNetrcService(client *scm.Client, renewer core.Renewer, config config.Config) core.NetrcService {
return netrc.New(
client,
renewer,
config.Cloning.AlwaysAuth,
config.Cloning.Username,
config.Cloning.Password,
)
}
// provideOrgService is a Wire provider function that
// returns an organization service wrapped with a simple cache.
func provideOrgService(client *scm.Client, renewer core.Renewer) core.OrganizationService {
return orgs.NewCache(orgs.New(client, renewer), 10, time.Minute*5)
}
// provideRepo is a Wire provider function that returns
// a repo based on the environment configuration
func provideRepositoryService(client *scm.Client, renewer core.Renewer, config config.Config) core.RepositoryService {
return repo.New(
client,
renewer,
config.Repository.Visibility,
config.Repository.Trusted,
)
}
// provideSession is a Wire provider function that returns a
// user session based on the environment configuration.
func provideSession(store core.UserStore, config config.Config) (core.Session, error) {
return session.New(store, session.NewConfig(
config.Session.Secret,
config.Session.Timeout,
config.Session.Secure),
), nil
}
// provideUserService is a Wire provider function that returns a
// user service based on the environment configuration.
func provideStatusService(client *scm.Client, renewer core.Renewer, config config.Config) core.StatusService {
return status.New(client, renewer, status.Config{
Base: config.Server.Addr,
Name: config.Status.Name,
Disabled: config.Status.Disabled,
})
}
// provideSyncer is a Wire provider function that returns a
// repository synchronizer.
func provideSyncer(repoz core.RepositoryService,
repos core.RepositoryStore,
users core.UserStore,
batch core.Batcher,
config config.Config) core.Syncer {
sync := syncer.New(repoz, repos, users, batch)
// the user can define a filter that limits which
// repositories can be synchronized and stored in the
// database.
if filter := config.Repository.Filter; len(filter) > 0 {
sync.SetFilter(syncer.NamespaceFilter(filter))
}
return sync
}
// provideSyncer is a Wire provider function that returns the
// system details structure.
func provideSystem(config config.Config) *core.System {
return &core.System{
Proto: config.Server.Proto,
Host: config.Server.Host,
Link: config.Server.Addr,
Version: version.Version.String(),
}
}
// provideReaper is a Wire provider function that returns the
// zombie build reaper.
func provideReaper(
repos core.RepositoryStore,
builds core.BuildStore,
stages core.StageStore,
canceler core.Canceler,
config config.Config,
) *reaper.Reaper {
return reaper.New(
repos,
builds,
stages,
canceler,
config.Cleanup.Running,
config.Cleanup.Pending,
config.Cleanup.Buffer,
)
}
// provideDatadog is a Wire provider function that returns the
// datadog sink.
func provideDatadog(
users core.UserStore,
repos core.RepositoryStore,
builds core.BuildStore,
system *core.System,
license *core.License,
config config.Config,
) *sink.Datadog {
return sink.New(
users,
repos,
builds,
*system,
sink.Config{
Endpoint: config.Datadog.Endpoint,
Token: config.Datadog.Token,
License: license.Kind,
Licensor: license.Licensor,
Subscription: license.Subscription,
EnableGithub: config.IsGitHub(),
EnableGithubEnt: config.IsGitHubEnterprise(),
EnableGitlab: config.IsGitLab(),
EnableBitbucket: config.IsBitbucket(),
EnableStash: config.IsStash(),
EnableGogs: config.IsGogs(),
EnableGitea: config.IsGitea(),
EnableGitee: config.IsGitee(),
EnableAgents: !config.Agent.Disabled,
},
)
}

View File

@ -1,181 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/metric"
"github.com/drone/drone/store/batch"
"github.com/drone/drone/store/batch2"
"github.com/drone/drone/store/build"
"github.com/drone/drone/store/card"
"github.com/drone/drone/store/cron"
"github.com/drone/drone/store/logs"
"github.com/drone/drone/store/perm"
"github.com/drone/drone/store/repos"
"github.com/drone/drone/store/secret"
"github.com/drone/drone/store/secret/global"
"github.com/drone/drone/store/shared/db"
"github.com/drone/drone/store/shared/encrypt"
"github.com/drone/drone/store/stage"
"github.com/drone/drone/store/step"
"github.com/drone/drone/store/template"
"github.com/drone/drone/store/user"
"github.com/google/wire"
"github.com/sirupsen/logrus"
)
// wire set for loading the stores.
var storeSet = wire.NewSet(
provideDatabase,
provideEncrypter,
provideBuildStore,
provideLogStore,
provideRepoStore,
provideStageStore,
provideUserStore,
provideBatchStore,
// batch.New,
cron.New,
card.New,
perm.New,
secret.New,
global.New,
step.New,
template.New,
)
// provideDatabase is a Wire provider function that provides a
// database connection, configured from the environment.
func provideDatabase(config config.Config) (*db.DB, error) {
return db.Connect(
config.Database.Driver,
config.Database.Datasource,
config.Database.MaxConnections,
)
}
// provideEncrypter is a Wire provider function that provides a
// database encrypter, configured from the environment.
func provideEncrypter(config config.Config) (encrypt.Encrypter, error) {
enc, err := encrypt.New(config.Database.Secret)
// mixed-content mode should be set to true if the database
// originally had encryption disabled and therefore has
// plaintext entries. This prevents Drone from returning an
// error if decryption fails; on failure, the ciphertext is
// returned as-is and the error is ignored.
if aesgcm, ok := enc.(*encrypt.Aesgcm); ok {
logrus.Debugln("main: database encryption enabled")
if config.Database.EncryptMixedContent {
logrus.Debugln("main: database encryption mixed-mode enabled")
aesgcm.Compat = true
}
}
return enc, err
}
// provideBuildStore is a Wire provider function that provides a
// build datastore, configured from the environment, with metrics
// enabled.
func provideBuildStore(db *db.DB) core.BuildStore {
builds := build.New(db)
metric.BuildCount(builds)
metric.PendingBuildCount(builds)
metric.RunningBuildCount(builds)
return builds
}
// provideLogStore is a Wire provider function that provides a
// log datastore, configured from the environment.
func provideLogStore(db *db.DB, config config.Config) core.LogStore {
s := logs.New(db)
if config.S3.Bucket != "" {
p := logs.NewS3Env(
config.S3.Bucket,
config.S3.Prefix,
config.S3.Endpoint,
config.S3.PathStyle,
)
return logs.NewCombined(p, s)
}
if config.AzureBlob.ContainerName != "" {
p := logs.NewAzureBlobEnv(
config.AzureBlob.ContainerName,
config.AzureBlob.StorageAccountName,
config.AzureBlob.StorageAccessKey,
)
return logs.NewCombined(p, s)
}
return s
}
// provideStageStore is a Wire provider function that provides a
// stage datastore, configured from the environment, with metrics
// enabled.
func provideStageStore(db *db.DB) core.StageStore {
stages := stage.New(db)
metric.PendingJobCount(stages)
metric.RunningJobCount(stages)
return stages
}
// provideRepoStore is a Wire provider function that provides a
// user datastore, configured from the environment, with metrics
// enabled.
func provideRepoStore(db *db.DB) core.RepositoryStore {
repos := repos.New(db)
metric.RepoCount(repos)
return repos
}
// provideBatchStore is a Wire provider function that provides a
// batcher. If the experimental batcher is enabled it is returned.
func provideBatchStore(db *db.DB, config config.Config) core.Batcher {
if config.Database.LegacyBatch {
return batch.New(db)
}
return batch2.New(db)
}
// provideUserStore is a Wire provider function that provides a
// user datastore, configured from the environment, with metrics
// enabled.
func provideUserStore(db *db.DB, enc encrypt.Encrypter, config config.Config) core.UserStore {
// create the user store with encryption iff the user
// encryption feature flag is enabled.
//
// why not enable by default? because the user table is
// accessed on every http request and we are unsure what,
// if any performance implications user table encryption
// may have on the system.
//
// it is very possible there are zero material performance
// implications, however, if there is a performance regression
// we could look at implementing in-memory lru caching, which
// we already employ in other areas of the software.
if config.Database.EncryptUserTable {
logrus.Debugln("main: database encryption enabled for user table")
users := user.New(db, enc)
metric.UserCount(users)
return users
}
noenc, _ := encrypt.New("")
users := user.New(db, noenc)
metric.UserCount(users)
return users
}

View File

@ -1,193 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"flag"
"fmt"
"github.com/drone/drone/cmd/drone-server/bootstrap"
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/core"
"github.com/drone/drone/metric/sink"
"github.com/drone/drone/operator/runner"
"github.com/drone/drone/service/canceler/reaper"
"github.com/drone/drone/server"
"github.com/drone/drone/trigger/cron"
"github.com/drone/signal"
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
func main() {
var envfile string
flag.StringVar(&envfile, "env-file", ".env", "Read in a file of environment variables")
flag.Parse()
godotenv.Load(envfile)
config, err := config.Environ()
if err != nil {
logger := logrus.WithError(err)
logger.Fatalln("main: invalid configuration")
}
initLogging(config)
ctx := signal.WithContext(
context.Background(),
)
// if trace level logging is enabled, output the
// configuration parameters.
if logrus.IsLevelEnabled(logrus.TraceLevel) {
fmt.Println(config.String())
}
app, err := InitializeApplication(config)
if err != nil {
logger := logrus.WithError(err)
logger.Fatalln("main: cannot initialize server")
}
// optionally bootstrap the system with administrative or
// machine users configured in the environment.
err = bootstrap.New(app.users).Bootstrap(ctx, &core.User{
Login: config.Users.Create.Username,
Machine: config.Users.Create.Machine,
Admin: config.Users.Create.Admin,
Hash: config.Users.Create.Token,
})
if err != nil {
logger := logrus.WithError(err)
logger.Fatalln("cannot bootstrap user account")
}
g := errgroup.Group{}
g.Go(func() error {
logrus.WithFields(
logrus.Fields{
"proto": config.Server.Proto,
"host": config.Server.Host,
"port": config.Server.Port,
"url": config.Server.Addr,
"acme": config.Server.Acme,
},
).Infoln("starting the http server")
return app.server.ListenAndServe(ctx)
})
// launches the datadog sink in a goroutine. If the sink
// is disabled, the goroutine exits immediately without error.
g.Go(func() (err error) {
if !config.Datadog.Enabled {
return nil
}
return app.sink.Start(ctx)
})
// launches the cron runner in a goroutine. If the cron
// runner is disabled, the goroutine exits immediately
// without error.
g.Go(func() (err error) {
if config.Cron.Disabled {
return nil
}
logrus.WithField("interval", config.Cron.Interval.String()).
Infoln("starting the cron scheduler")
return app.cron.Start(ctx, config.Cron.Interval)
})
// launches the reaper in a goroutine. If the reaper
// is disabled, the goroutine exits immediately
// without error.
g.Go(func() (err error) {
if config.Cleanup.Disabled {
return nil
}
logrus.WithField("interval", config.Cleanup.Interval.String()).
Infoln("starting the zombie build reaper")
return app.reaper.Start(ctx, config.Cleanup.Interval)
})
// launches the build runner in a goroutine. If the local
// runner is disabled (because nomad or kubernetes is enabled)
// then the goroutine exits immediately without error.
g.Go(func() (err error) {
if app.runner == nil {
return nil
}
logrus.WithField("threads", config.Runner.Capacity).
Infoln("main: starting the local build runner")
return app.runner.Start(ctx, config.Runner.Capacity)
})
if err := g.Wait(); err != nil {
logrus.WithError(err).Fatalln("program terminated")
}
}
// helper function configures the logging.
func initLogging(c config.Config) {
if c.Logging.Debug {
logrus.SetLevel(logrus.DebugLevel)
}
if c.Logging.Trace {
logrus.SetLevel(logrus.TraceLevel)
}
if c.Logging.Text {
logrus.SetFormatter(&logrus.TextFormatter{
ForceColors: c.Logging.Color,
DisableColors: !c.Logging.Color,
})
} else {
logrus.SetFormatter(&logrus.JSONFormatter{
PrettyPrint: c.Logging.Pretty,
})
}
}
// application is the main struct for the Drone server.
type application struct {
cron *cron.Scheduler
reaper *reaper.Reaper
sink *sink.Datadog
runner *runner.Runner
server *server.Server
users core.UserStore
}
// newApplication creates a new application struct.
func newApplication(
cron *cron.Scheduler,
reaper *reaper.Reaper,
sink *sink.Datadog,
runner *runner.Runner,
server *server.Server,
users core.UserStore) application {
return application{
users: users,
cron: cron,
sink: sink,
server: server,
runner: runner,
reaper: reaper,
}
}

View File

@ -1,39 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//+build wireinject
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/google/wire"
)
func InitializeApplication(config config.Config) (application, error) {
wire.Build(
clientSet,
licenseSet,
loginSet,
pluginSet,
runnerSet,
schedulerSet,
serverSet,
serviceSet,
storeSet,
externalSet,
newApplication,
)
return application{}, nil
}

View File

@ -1,120 +0,0 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
package main
import (
"github.com/drone/drone/cmd/drone-server/config"
"github.com/drone/drone/handler/api"
"github.com/drone/drone/handler/web"
"github.com/drone/drone/livelog"
"github.com/drone/drone/operator/manager"
"github.com/drone/drone/pubsub"
"github.com/drone/drone/service/canceler"
"github.com/drone/drone/service/commit"
"github.com/drone/drone/service/hook/parser"
"github.com/drone/drone/service/license"
"github.com/drone/drone/service/linker"
"github.com/drone/drone/service/token"
"github.com/drone/drone/service/transfer"
"github.com/drone/drone/service/user"
"github.com/drone/drone/store/card"
"github.com/drone/drone/store/cron"
"github.com/drone/drone/store/perm"
"github.com/drone/drone/store/secret"
"github.com/drone/drone/store/secret/global"
"github.com/drone/drone/store/step"
"github.com/drone/drone/store/template"
"github.com/drone/drone/trigger"
cron2 "github.com/drone/drone/trigger/cron"
)
import (
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
// Injectors from wire.go:
func InitializeApplication(config2 config.Config) (application, error) {
client := provideClient(config2)
refresher := provideRefresher(config2)
db, err := provideDatabase(config2)
if err != nil {
return application{}, err
}
encrypter, err := provideEncrypter(config2)
if err != nil {
return application{}, err
}
userStore := provideUserStore(db, encrypter, config2)
renewer := token.Renewer(refresher, userStore)
commitService := commit.New(client, renewer)
cronStore := cron.New(db)
repositoryStore := provideRepoStore(db)
buildStore := provideBuildStore(db)
redisDB, err := provideRedisClient(config2)
if err != nil {
return application{}, err
}
corePubsub := pubsub.New(redisDB)
stageStore := provideStageStore(db)
scheduler := provideScheduler(stageStore, redisDB)
statusService := provideStatusService(client, renewer, config2)
stepStore := step.New(db)
system := provideSystem(config2)
webhookSender := provideWebhookPlugin(config2, system)
coreCanceler := canceler.New(buildStore, corePubsub, repositoryStore, scheduler, stageStore, statusService, stepStore, userStore, webhookSender)
fileService := provideContentService(client, renewer)
configService := provideConfigPlugin(client, fileService, config2)
templateStore := template.New(db)
convertService := provideConvertPlugin(client, fileService, config2, templateStore)
validateService := provideValidatePlugin(config2)
triggerer := trigger.New(coreCanceler, configService, convertService, commitService, statusService, buildStore, scheduler, repositoryStore, userStore, validateService, webhookSender)
cronScheduler := cron2.New(commitService, cronStore, repositoryStore, userStore, triggerer)
reaper := provideReaper(repositoryStore, buildStore, stageStore, coreCanceler, config2)
coreLicense := provideLicense(client, config2)
datadog := provideDatadog(userStore, repositoryStore, buildStore, system, coreLicense, config2)
cardStore := card.New(db)
logStore := provideLogStore(db, config2)
logStream := livelog.New(redisDB)
netrcService := provideNetrcService(client, renewer, config2)
secretStore := secret.New(db, encrypter)
globalSecretStore := global.New(db, encrypter)
buildManager := manager.New(buildStore, cardStore, configService, convertService, corePubsub, logStore, logStream, netrcService, repositoryStore, scheduler, secretStore, globalSecretStore, statusService, stageStore, stepStore, system, userStore, webhookSender)
secretService := provideSecretPlugin(config2)
registryService := provideRegistryPlugin(config2)
runner := provideRunner(buildManager, secretService, registryService, config2)
hookService := provideHookService(client, renewer, config2)
licenseService := license.NewService(userStore, repositoryStore, buildStore, coreLicense)
organizationService := provideOrgService(client, renewer)
permStore := perm.New(db)
repositoryService := provideRepositoryService(client, renewer, config2)
session, err := provideSession(userStore, config2)
if err != nil {
return application{}, err
}
batcher := provideBatchStore(db, config2)
syncer := provideSyncer(repositoryService, repositoryStore, userStore, batcher, config2)
transferer := transfer.New(repositoryStore, permStore)
userService := user.New(client, renewer)
server := api.New(buildStore, commitService, cardStore, cronStore, corePubsub, globalSecretStore, hookService, logStore, coreLicense, licenseService, organizationService, permStore, repositoryStore, repositoryService, scheduler, secretStore, stageStore, stepStore, statusService, session, logStream, syncer, system, templateStore, transferer, triggerer, userStore, userService, webhookSender)
admissionService := provideAdmissionPlugin(client, organizationService, userService, config2)
hookParser := parser.New(client)
coreLinker := linker.New(client)
middleware := provideLogin(config2)
options := provideServerOptions(config2)
webServer := web.New(admissionService, buildStore, client, hookParser, coreLicense, licenseService, coreLinker, middleware, repositoryStore, session, syncer, triggerer, userStore, userService, webhookSender, options, system)
mainRpcHandlerV1 := provideRPC(buildManager, config2)
mainRpcHandlerV2 := provideRPC2(buildManager, config2)
mainHealthzHandler := provideHealthz()
metricServer := provideMetric(session, config2)
mainPprofHandler := providePprof(config2)
mux := provideRouter(server, webServer, mainRpcHandlerV1, mainRpcHandlerV2, mainHealthzHandler, metricServer, mainPprofHandler)
serverServer := provideServer(mux, config2)
mainApplication := newApplication(cronScheduler, reaper, datadog, runner, serverServer, userStore)
return mainApplication, nil
}

View File

@ -0,0 +1,45 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"os"
"github.com/harness/gitness/githook"
gitnessgithook "github.com/harness/gitness/internal/githook"
"github.com/harness/gitness/version"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
application = "gitness-githook"
description = "A lightweight executable that forwards git server hooks to the gitness API server."
)
func main() {
// ensure args are properly sanitized if called by git
command := os.Args[0]
args := os.Args[1:]
args, _ = githook.SanitizeArgsForGit(command, args)
// define new kingpin application and register githooks globally
app := kingpin.New(application, description)
app.Version(version.Version.String())
githook.RegisterAll(app, gitnessgithook.LoadFromEnvironment)
// trigger execution
kingpin.MustParse(app.Parse(args))
}

22
cmd/gitness/driver_pq.go Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build pq
// +build pq
package main
import (
_ "github.com/lib/pq"
)

View File

@ -0,0 +1,22 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build sqlite
// +build sqlite
package main
import (
_ "github.com/mattn/go-sqlite3"
)

56
cmd/gitness/main.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/harness/gitness/cli"
"github.com/harness/gitness/cli/operations/account"
"github.com/harness/gitness/cli/operations/hooks"
"github.com/harness/gitness/cli/operations/migrate"
"github.com/harness/gitness/cli/operations/user"
"github.com/harness/gitness/cli/operations/users"
"github.com/harness/gitness/cli/server"
"github.com/harness/gitness/version"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
application = "gitness"
description = "Gitness Open source edition"
)
func main() {
args := cli.GetArguments()
app := kingpin.New(application, description)
migrate.Register(app)
server.Register(app, initSystem)
user.Register(app)
users.Register(app)
account.RegisterLogin(app)
account.RegisterRegister(app)
account.RegisterLogout(app)
hooks.Register(app)
cli.RegisterSwagger(app)
kingpin.Version(version.Version.String())
kingpin.MustParse(app.Parse(args))
}

148
cmd/gitness/wire.go Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2021 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
//go:build wireinject
// +build wireinject
package main
import (
"context"
cliserver "github.com/harness/gitness/cli/server"
"github.com/harness/gitness/encrypt"
"github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc"
gitrpcserver "github.com/harness/gitness/gitrpc/server"
gitrpccron "github.com/harness/gitness/gitrpc/server/cron"
checkcontroller "github.com/harness/gitness/internal/api/controller/check"
"github.com/harness/gitness/internal/api/controller/connector"
"github.com/harness/gitness/internal/api/controller/execution"
"github.com/harness/gitness/internal/api/controller/githook"
controllerlogs "github.com/harness/gitness/internal/api/controller/logs"
"github.com/harness/gitness/internal/api/controller/pipeline"
"github.com/harness/gitness/internal/api/controller/plugin"
"github.com/harness/gitness/internal/api/controller/principal"
"github.com/harness/gitness/internal/api/controller/pullreq"
"github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/api/controller/secret"
"github.com/harness/gitness/internal/api/controller/service"
"github.com/harness/gitness/internal/api/controller/serviceaccount"
"github.com/harness/gitness/internal/api/controller/space"
"github.com/harness/gitness/internal/api/controller/system"
"github.com/harness/gitness/internal/api/controller/template"
controllertrigger "github.com/harness/gitness/internal/api/controller/trigger"
"github.com/harness/gitness/internal/api/controller/user"
controllerwebhook "github.com/harness/gitness/internal/api/controller/webhook"
"github.com/harness/gitness/internal/auth/authn"
"github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/bootstrap"
gitevents "github.com/harness/gitness/internal/events/git"
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/internal/pipeline/canceler"
"github.com/harness/gitness/internal/pipeline/commit"
"github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/manager"
pluginmanager "github.com/harness/gitness/internal/pipeline/plugin"
"github.com/harness/gitness/internal/pipeline/runner"
"github.com/harness/gitness/internal/pipeline/scheduler"
"github.com/harness/gitness/internal/pipeline/triggerer"
"github.com/harness/gitness/internal/router"
"github.com/harness/gitness/internal/server"
"github.com/harness/gitness/internal/services"
"github.com/harness/gitness/internal/services/codecomments"
"github.com/harness/gitness/internal/services/exporter"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/internal/services/metric"
pullreqservice "github.com/harness/gitness/internal/services/pullreq"
"github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/internal/sse"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/cache"
"github.com/harness/gitness/internal/store/database"
"github.com/harness/gitness/internal/store/logs"
"github.com/harness/gitness/internal/url"
"github.com/harness/gitness/livelog"
"github.com/harness/gitness/lock"
"github.com/harness/gitness/pubsub"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
"github.com/google/wire"
)
func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, error) {
wire.Build(
cliserver.NewSystem,
cliserver.ProvideRedis,
bootstrap.WireSet,
cliserver.ProvideDatabaseConfig,
database.WireSet,
cache.WireSet,
router.WireSet,
pullreqservice.WireSet,
services.WireSet,
server.WireSet,
url.WireSet,
space.WireSet,
repo.WireSet,
pullreq.WireSet,
controllerwebhook.WireSet,
serviceaccount.WireSet,
user.WireSet,
service.WireSet,
principal.WireSet,
system.WireSet,
authn.WireSet,
authz.WireSet,
gitevents.WireSet,
pullreqevents.WireSet,
cliserver.ProvideGitRPCServerConfig,
gitrpcserver.WireSet,
cliserver.ProvideGitRPCClientConfig,
gitrpc.WireSet,
store.WireSet,
check.WireSet,
encrypt.WireSet,
cliserver.ProvideEventsConfig,
events.WireSet,
cliserver.ProvideWebhookConfig,
webhook.WireSet,
cliserver.ProvideTriggerConfig,
trigger.WireSet,
githook.WireSet,
cliserver.ProvideLockConfig,
lock.WireSet,
pubsub.WireSet,
codecomments.WireSet,
job.WireSet,
gitrpccron.WireSet,
checkcontroller.WireSet,
execution.WireSet,
pipeline.WireSet,
logs.WireSet,
livelog.WireSet,
controllerlogs.WireSet,
secret.WireSet,
connector.WireSet,
template.WireSet,
manager.WireSet,
triggerer.WireSet,
file.WireSet,
runner.WireSet,
sse.WireSet,
scheduler.WireSet,
commit.WireSet,
controllertrigger.WireSet,
plugin.WireSet,
pluginmanager.WireSet,
importer.WireSet,
canceler.WireSet,
exporter.WireSet,
metric.WireSet,
)
return &cliserver.System{}, nil
}

260
cmd/gitness/wire_gen.go Normal file
View File

@ -0,0 +1,260 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"context"
"github.com/harness/gitness/cli/server"
"github.com/harness/gitness/encrypt"
"github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc"
server3 "github.com/harness/gitness/gitrpc/server"
"github.com/harness/gitness/gitrpc/server/cron"
check2 "github.com/harness/gitness/internal/api/controller/check"
"github.com/harness/gitness/internal/api/controller/connector"
"github.com/harness/gitness/internal/api/controller/execution"
"github.com/harness/gitness/internal/api/controller/githook"
logs2 "github.com/harness/gitness/internal/api/controller/logs"
"github.com/harness/gitness/internal/api/controller/pipeline"
"github.com/harness/gitness/internal/api/controller/plugin"
"github.com/harness/gitness/internal/api/controller/principal"
pullreq2 "github.com/harness/gitness/internal/api/controller/pullreq"
"github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/api/controller/secret"
"github.com/harness/gitness/internal/api/controller/service"
"github.com/harness/gitness/internal/api/controller/serviceaccount"
"github.com/harness/gitness/internal/api/controller/space"
"github.com/harness/gitness/internal/api/controller/system"
"github.com/harness/gitness/internal/api/controller/template"
"github.com/harness/gitness/internal/api/controller/trigger"
"github.com/harness/gitness/internal/api/controller/user"
webhook2 "github.com/harness/gitness/internal/api/controller/webhook"
"github.com/harness/gitness/internal/auth/authn"
"github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/bootstrap"
events3 "github.com/harness/gitness/internal/events/git"
events2 "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/internal/pipeline/canceler"
"github.com/harness/gitness/internal/pipeline/commit"
"github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/manager"
plugin2 "github.com/harness/gitness/internal/pipeline/plugin"
"github.com/harness/gitness/internal/pipeline/runner"
"github.com/harness/gitness/internal/pipeline/scheduler"
"github.com/harness/gitness/internal/pipeline/triggerer"
"github.com/harness/gitness/internal/router"
server2 "github.com/harness/gitness/internal/server"
"github.com/harness/gitness/internal/services"
"github.com/harness/gitness/internal/services/codecomments"
"github.com/harness/gitness/internal/services/exporter"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/internal/services/metric"
"github.com/harness/gitness/internal/services/pullreq"
trigger2 "github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/internal/sse"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/cache"
"github.com/harness/gitness/internal/store/database"
"github.com/harness/gitness/internal/store/logs"
"github.com/harness/gitness/internal/url"
"github.com/harness/gitness/livelog"
"github.com/harness/gitness/lock"
"github.com/harness/gitness/pubsub"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/check"
)
// Injectors from wire.go:
func initSystem(ctx context.Context, config *types.Config) (*server.System, error) {
databaseConfig := server.ProvideDatabaseConfig(config)
db, err := database.ProvideDatabase(ctx, databaseConfig)
if err != nil {
return nil, err
}
principalUID := check.ProvidePrincipalUIDCheck()
spacePathTransformation := store.ProvidePathTransformation()
spacePathStore := database.ProvideSpacePathStore(db, spacePathTransformation)
spacePathCache := cache.ProvidePathCache(spacePathStore, spacePathTransformation)
spaceStore := database.ProvideSpaceStore(db, spacePathCache, spacePathStore)
principalInfoView := database.ProvidePrincipalInfoView(db)
principalInfoCache := cache.ProvidePrincipalInfoCache(principalInfoView)
membershipStore := database.ProvideMembershipStore(db, principalInfoCache, spacePathStore)
permissionCache := authz.ProvidePermissionCache(spaceStore, membershipStore)
authorizer := authz.ProvideAuthorizer(permissionCache, spaceStore)
principalUIDTransformation := store.ProvidePrincipalUIDTransformation()
principalStore := database.ProvidePrincipalStore(db, principalUIDTransformation)
tokenStore := database.ProvideTokenStore(db)
controller := user.ProvideController(db, principalUID, authorizer, principalStore, tokenStore, membershipStore)
serviceController := service.NewController(principalUID, authorizer, principalStore)
bootstrapBootstrap := bootstrap.ProvideBootstrap(config, controller, serviceController)
authenticator := authn.ProvideAuthenticator(config, principalStore, tokenStore)
provider, err := url.ProvideURLProvider(config)
if err != nil {
return nil, err
}
pathUID := check.ProvidePathUIDCheck()
repoStore := database.ProvideRepoStore(db, spacePathCache, spacePathStore)
pipelineStore := database.ProvidePipelineStore(db)
gitrpcConfig, err := server.ProvideGitRPCClientConfig()
if err != nil {
return nil, err
}
gitrpcInterface, err := gitrpc.ProvideClient(gitrpcConfig)
if err != nil {
return nil, err
}
triggerStore := database.ProvideTriggerStore(db)
encrypter, err := encrypt.ProvideEncrypter(config)
if err != nil {
return nil, err
}
jobStore := database.ProvideJobStore(db)
pubsubConfig := pubsub.ProvideConfig(config)
universalClient, err := server.ProvideRedis(config)
if err != nil {
return nil, err
}
pubSub := pubsub.ProvidePubSub(pubsubConfig, universalClient)
executor := job.ProvideExecutor(jobStore, pubSub)
lockConfig := server.ProvideLockConfig(config)
mutexManager := lock.ProvideMutexManager(lockConfig, universalClient)
jobScheduler, err := job.ProvideScheduler(jobStore, executor, mutexManager, pubSub, config)
if err != nil {
return nil, err
}
streamer := sse.ProvideEventsStreaming(pubSub)
repository, err := importer.ProvideRepoImporter(config, provider, gitrpcInterface, db, repoStore, pipelineStore, triggerStore, encrypter, jobScheduler, executor, streamer)
if err != nil {
return nil, err
}
repoController := repo.ProvideController(config, db, provider, pathUID, authorizer, repoStore, spaceStore, pipelineStore, principalStore, gitrpcInterface, repository)
executionStore := database.ProvideExecutionStore(db)
checkStore := database.ProvideCheckStore(db, principalInfoCache)
stageStore := database.ProvideStageStore(db)
schedulerScheduler, err := scheduler.ProvideScheduler(stageStore, mutexManager)
if err != nil {
return nil, err
}
stepStore := database.ProvideStepStore(db)
cancelerCanceler := canceler.ProvideCanceler(executionStore, streamer, repoStore, schedulerScheduler, stageStore, stepStore)
commitService := commit.ProvideCommitService(gitrpcInterface)
fileService := file.ProvideFileService(gitrpcInterface)
triggererTriggerer := triggerer.ProvideTriggerer(executionStore, checkStore, stageStore, db, pipelineStore, fileService, schedulerScheduler, repoStore)
executionController := execution.ProvideController(db, authorizer, executionStore, checkStore, cancelerCanceler, commitService, triggererTriggerer, repoStore, stageStore, pipelineStore)
logStore := logs.ProvideLogStore(db, config)
logStream := livelog.ProvideLogStream(config)
logsController := logs2.ProvideController(db, authorizer, executionStore, repoStore, pipelineStore, stageStore, stepStore, logStore, logStream)
secretStore := database.ProvideSecretStore(db)
connectorStore := database.ProvideConnectorStore(db)
templateStore := database.ProvideTemplateStore(db)
exporterRepository, err := exporter.ProvideSpaceExporter(provider, gitrpcInterface, repoStore, jobScheduler, executor, encrypter, streamer)
if err != nil {
return nil, err
}
spaceController := space.ProvideController(config, db, provider, streamer, pathUID, authorizer, spacePathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore, repository, exporterRepository)
pipelineController := pipeline.ProvideController(db, pathUID, repoStore, triggerStore, authorizer, pipelineStore)
secretController := secret.ProvideController(db, pathUID, encrypter, secretStore, authorizer, spaceStore)
triggerController := trigger.ProvideController(db, authorizer, triggerStore, pathUID, pipelineStore, repoStore)
connectorController := connector.ProvideController(db, pathUID, connectorStore, authorizer, spaceStore)
templateController := template.ProvideController(db, pathUID, templateStore, authorizer, spaceStore)
pluginStore := database.ProvidePluginStore(db)
pluginController := plugin.ProvideController(db, pluginStore)
pullReqStore := database.ProvidePullReqStore(db, principalInfoCache)
pullReqActivityStore := database.ProvidePullReqActivityStore(db, principalInfoCache)
codeCommentView := database.ProvideCodeCommentView(db)
pullReqReviewStore := database.ProvidePullReqReviewStore(db)
pullReqReviewerStore := database.ProvidePullReqReviewerStore(db, principalInfoCache)
pullReqFileViewStore := database.ProvidePullReqFileViewStore(db)
eventsConfig, err := server.ProvideEventsConfig()
if err != nil {
return nil, err
}
eventsSystem, err := events.ProvideSystem(eventsConfig, universalClient)
if err != nil {
return nil, err
}
reporter, err := events2.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
migrator := codecomments.ProvideMigrator(gitrpcInterface)
readerFactory, err := events3.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
eventsReaderFactory, err := events2.ProvideReaderFactory(eventsSystem)
if err != nil {
return nil, err
}
repoGitInfoView := database.ProvideRepoGitInfoView(db)
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
pullreqService, err := pullreq.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pullReqFileViewStore, pubSub, provider, streamer)
if err != nil {
return nil, err
}
pullreqController := pullreq2.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, pullReqFileViewStore, gitrpcInterface, reporter, mutexManager, migrator, pullreqService, streamer)
webhookConfig := server.ProvideWebhookConfig(config)
webhookStore := database.ProvideWebhookStore(db)
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
webhookService, err := webhook.ProvideService(ctx, webhookConfig, readerFactory, eventsReaderFactory, webhookStore, webhookExecutionStore, repoStore, pullReqStore, provider, principalStore, gitrpcInterface, encrypter)
if err != nil {
return nil, err
}
webhookController := webhook2.ProvideController(webhookConfig, db, authorizer, webhookStore, webhookExecutionStore, repoStore, webhookService, encrypter)
eventsReporter, err := events3.ProvideReporter(eventsSystem)
if err != nil {
return nil, err
}
githookController := githook.ProvideController(db, authorizer, principalStore, repoStore, eventsReporter)
serviceaccountController := serviceaccount.NewController(principalUID, authorizer, principalStore, spaceStore, repoStore, tokenStore)
principalController := principal.ProvideController(principalStore)
checkController := check2.ProvideController(db, authorizer, repoStore, checkStore, gitrpcInterface)
systemController := system.NewController(principalStore, config)
apiHandler := router.ProvideAPIHandler(config, authenticator, repoController, executionController, logsController, spaceController, pipelineController, secretController, triggerController, connectorController, templateController, pluginController, pullreqController, webhookController, githookController, serviceaccountController, controller, principalController, checkController, systemController)
gitHandler := router.ProvideGitHandler(config, provider, repoStore, authenticator, authorizer, gitrpcInterface)
webHandler := router.ProvideWebHandler(config)
routerRouter := router.ProvideRouter(config, apiHandler, gitHandler, webHandler)
serverServer := server2.ProvideServer(config, routerRouter)
executionManager := manager.ProvideExecutionManager(config, executionStore, pipelineStore, provider, streamer, fileService, logStore, logStream, checkStore, repoStore, schedulerScheduler, secretStore, stageStore, stepStore, principalStore)
client := manager.ProvideExecutionClient(executionManager, config)
pluginManager := plugin2.ProvidePluginManager(config, pluginStore)
runtimeRunner, err := runner.ProvideExecutionRunner(config, client, pluginManager, executionManager)
if err != nil {
return nil, err
}
poller := runner.ProvideExecutionPoller(runtimeRunner, config, client)
serverConfig, err := server.ProvideGitRPCServerConfig()
if err != nil {
return nil, err
}
goGitRepoProvider := server3.ProvideGoGitRepoProvider()
cacheCache := server3.ProvideLastCommitCache(serverConfig, universalClient, goGitRepoProvider)
gitAdapter, err := server3.ProvideGITAdapter(goGitRepoProvider, cacheCache)
if err != nil {
return nil, err
}
grpcServer, err := server3.ProvideServer(serverConfig, gitAdapter)
if err != nil {
return nil, err
}
cronManager := cron.ProvideManager(serverConfig)
triggerConfig := server.ProvideTriggerConfig(config)
triggerService, err := trigger2.ProvideService(ctx, triggerConfig, triggerStore, commitService, pullReqStore, repoStore, pipelineStore, triggererTriggerer, readerFactory, eventsReaderFactory)
if err != nil {
return nil, err
}
collector, err := metric.ProvideCollector(config, principalStore, repoStore, pipelineStore, executionStore, jobScheduler, executor)
if err != nil {
return nil, err
}
servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector)
serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, poller, grpcServer, pluginManager, cronManager, servicesServices)
return serverSystem, nil
}

View File

@ -0,0 +1,68 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/harness/gitness/gitrpc/server"
"github.com/kelseyhightower/envconfig"
)
type Config struct {
Debug bool `envconfig:"GITRPC_SERVER_DEBUG"`
Trace bool `envconfig:"GITRPC_SERVER_TRACE"`
// GracefulShutdownTime defines the max time we wait when shutting down a server.
// 5min should be enough for most git clones to complete.
GracefulShutdownTime time.Duration `envconfig:"GITRPC_SERVER_GRACEFUL_SHUTDOWN_TIME" default:"300s"`
Profiler struct {
Type string `envconfig:"GITRPC_PROFILER_TYPE"`
ServiceName string `envconfig:"GITRPC_PROFILER_SERVICE_NAME" default:"gitrpcserver"`
}
}
func loadConfig() (Config, error) {
config := Config{}
err := envconfig.Process("", &config)
if err != nil {
return Config{}, fmt.Errorf("processing of config failed: %w", err)
}
return config, nil
}
func ProvideGitRPCServerConfig() (server.Config, error) {
config := server.Config{}
err := envconfig.Process("", &config)
if err != nil {
return server.Config{}, fmt.Errorf("processing of gitrpc server config failed: %w", err)
}
if config.GitRoot == "" {
var homedir string
homedir, err = os.UserHomeDir()
if err != nil {
return server.Config{}, err
}
config.GitRoot = filepath.Join(homedir, ".gitrpc")
}
return config, nil
}

160
cmd/gitrpcserver/main.go Normal file
View File

@ -0,0 +1,160 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/harness/gitness/profiler"
"github.com/harness/gitness/version"
"github.com/joho/godotenv"
"github.com/mattn/go-isatty"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"golang.org/x/sync/errgroup"
"gopkg.in/alecthomas/kingpin.v2"
)
const (
application = "gitrpcserver"
description = "GitRPC is a GRPC server that exposes git via RPC."
)
func main() {
// define new kingpin application with global entry point
app := kingpin.New(application, description)
app.Version(version.Version.String())
var envFile string
app.Action(func(*kingpin.ParseContext) error { return run(envFile) })
app.Arg("envfile", "load the environment variable file").
Default("").
StringVar(&envFile)
// trigger execution
kingpin.MustParse(app.Parse(os.Args[1:]))
}
func run(envFile string) error {
// Create context that listens for the interrupt signal from the OS.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
if envFile != "" {
if err := godotenv.Load(envFile); err != nil {
return fmt.Errorf("failed to load environment file: %w", err)
}
}
config, err := loadConfig()
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
// setup logger and inject into context
setupLogger(config)
log := log.Logger.With().Logger()
ctx = log.WithContext(ctx)
setupProfiler(config)
system, err := initSystem()
if err != nil {
return fmt.Errorf("failed to init gitrpc server: %w", err)
}
// gCtx is canceled if any of the following occurs:
// - any go routine launched with g encounters an error
// - ctx is canceled
g, gCtx := errgroup.WithContext(ctx)
// start grpc server
g.Go(system.grpcServer.Start)
log.Info().Msg("grpc server started")
gHTTP, shutdownHTTP := system.httpServer.ListenAndServe()
g.Go(gHTTP.Wait)
log.Info().Msgf("http server started")
// wait until the error group context is done
<-gCtx.Done()
// restore default behavior on the interrupt signal and notify user of shutdown.
stop()
log.Info().Msg("shutting down gracefully (press Ctrl+C again to force)")
// shutdown servers gracefully
shutdownCtx, cancel := context.WithTimeout(context.Background(), config.GracefulShutdownTime)
defer cancel()
if rpcErr := system.grpcServer.Stop(); rpcErr != nil {
log.Err(rpcErr).Msg("failed to shutdown grpc server gracefully")
}
if sErr := shutdownHTTP(shutdownCtx); sErr != nil {
log.Err(sErr).Msg("failed to shutdown http server gracefully")
}
log.Info().Msg("wait for subroutines to complete")
err = g.Wait()
return err
}
// helper function configures the global logger from
// the loaded configuration.
func setupLogger(config Config) {
// configure the log level
switch {
case config.Trace:
zerolog.SetGlobalLevel(zerolog.TraceLevel)
case config.Debug:
zerolog.SetGlobalLevel(zerolog.DebugLevel)
default:
zerolog.SetGlobalLevel(zerolog.InfoLevel)
}
// configure time format (ignored if running in terminal)
zerolog.TimeFieldFormat = time.RFC3339Nano
// if the terminal is a tty we should output the
// logs in pretty format
if isatty.IsTerminal(os.Stdout.Fd()) {
log.Logger = log.Output(
zerolog.ConsoleWriter{
Out: os.Stderr,
NoColor: false,
TimeFormat: "15:04:05.999",
},
)
}
}
func setupProfiler(config Config) {
profilerType, parsed := profiler.ParseType(config.Profiler.Type)
if !parsed {
log.Info().Msgf("No valid profiler so skipping profiling ['%s']", config.Profiler.Type)
return
}
gitrpcProfiler, _ := profiler.New(profilerType)
gitrpcProfiler.StartProfiling(config.Profiler.ServiceName, version.Version.String())
}

54
cmd/gitrpcserver/redis.go Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"strings"
"github.com/harness/gitness/gitrpc/server"
"github.com/go-redis/redis/v8"
)
// ProvideRedis provides a redis client based on the configuration.
// TODO: add support for TLS
func ProvideRedis(config server.Config) redis.UniversalClient {
if config.Redis.SentinelMode {
addrs := strings.Split(config.Redis.SentinelEndpoint, ",")
failoverOptions := &redis.FailoverOptions{
MasterName: config.Redis.SentinelMaster,
SentinelAddrs: addrs,
MaxRetries: config.Redis.MaxRetries,
MinIdleConns: config.Redis.MinIdleConnections,
}
if config.Redis.Password != "" {
failoverOptions.Password = config.Redis.Password
}
return redis.NewFailoverClient(failoverOptions)
}
options := &redis.Options{
Addr: config.Redis.Endpoint,
MaxRetries: config.Redis.MaxRetries,
MinIdleConns: config.Redis.MinIdleConnections,
}
if config.Redis.Password != "" {
options.Password = config.Redis.Password
}
return redis.NewClient(options)
}

View File

@ -0,0 +1,33 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/harness/gitness/gitrpc/server"
)
// system stores high level system components.
type system struct {
grpcServer *server.GRPCServer
httpServer *server.HTTPServer
}
// newSystem returns a new system structure.
func newSystem(grpcServer *server.GRPCServer, httpServer *server.HTTPServer) *system {
return &system{
grpcServer: grpcServer,
httpServer: httpServer,
}
}

24
cmd/gitrpcserver/wire.go Normal file
View File

@ -0,0 +1,24 @@
// Copyright 2021 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
//go:build wireinject
// +build wireinject
package main
import (
"github.com/harness/gitness/gitrpc/server"
"github.com/google/wire"
)
func initSystem() (*system, error) {
wire.Build(
newSystem,
ProvideGitRPCServerConfig,
server.WireSet,
ProvideRedis,
)
return &system{}, nil
}

View File

@ -0,0 +1,37 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"github.com/harness/gitness/gitrpc/server"
)
// Injectors from wire.go:
func initSystem() (*system, error) {
config, err := ProvideGitRPCServerConfig()
if err != nil {
return nil, err
}
goGitRepoProvider := server.ProvideGoGitRepoProvider()
universalClient := ProvideRedis(config)
cache := server.ProvideLastCommitCache(config, universalClient, goGitRepoProvider)
gitAdapter, err := server.ProvideGITAdapter(goGitRepoProvider, cache)
if err != nil {
return nil, err
}
grpcServer, err := server.ProvideServer(config, gitAdapter)
if err != nil {
return nil, err
}
httpServer, err := server.ProvideHTTPServer(config)
if err != nil {
return nil, err
}
mainSystem := newSystem(grpcServer, httpServer)
return mainSystem, nil
}

View File

@ -1,25 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
// AdmissionService grants access to the system. The service can
// be used to restrict access to authorized users, such as
// members of an organization in your source control management
// system.
type AdmissionService interface {
Admit(context.Context, *User) error
}

View File

@ -1,31 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
// Batch represents a Batch request to synchronize the local
// repository and permission store for a user account.
type Batch struct {
Insert []*Repository `json:"insert"`
Update []*Repository `json:"update"`
Rename []*Repository `json:"rename"`
Revoke []*Repository `json:"revoke"`
}
// Batcher batch updates the user account.
type Batcher interface {
Batch(context.Context, *User, *Batch) error
}

View File

@ -1,143 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
// Build represents a build execution.
type Build struct {
ID int64 `db:"build_id" json:"id"`
RepoID int64 `db:"build_repo_id" json:"repo_id"`
Trigger string `db:"build_trigger" json:"trigger"`
Number int64 `db:"build_number" json:"number"`
Parent int64 `db:"build_parent" json:"parent,omitempty"`
Status string `db:"build_status" json:"status"`
Error string `db:"build_error" json:"error,omitempty"`
Event string `db:"build_event" json:"event"`
Action string `db:"build_action" json:"action"`
Link string `db:"build_link" json:"link"`
Timestamp int64 `db:"build_timestamp" json:"timestamp"`
Title string `db:"build_title" json:"title,omitempty"`
Message string `db:"build_message" json:"message"`
Before string `db:"build_before" json:"before"`
After string `db:"build_after" json:"after"`
Ref string `db:"build_ref" json:"ref"`
Fork string `db:"build_source_repo" json:"source_repo"`
Source string `db:"build_source" json:"source"`
Target string `db:"build_target" json:"target"`
Author string `db:"build_author" json:"author_login"`
AuthorName string `db:"build_author_name" json:"author_name"`
AuthorEmail string `db:"build_author_email" json:"author_email"`
AuthorAvatar string `db:"build_author_avatar" json:"author_avatar"`
Sender string `db:"build_sender" json:"sender"`
Params map[string]string `db:"build_params" json:"params,omitempty"`
Cron string `db:"build_cron" json:"cron,omitempty"`
Deploy string `db:"build_deploy" json:"deploy_to,omitempty"`
DeployID int64 `db:"build_deploy_id" json:"deploy_id,omitempty"`
Debug bool `db:"build_debug" json:"debug,omitempty"`
Started int64 `db:"build_started" json:"started"`
Finished int64 `db:"build_finished" json:"finished"`
Created int64 `db:"build_created" json:"created"`
Updated int64 `db:"build_updated" json:"updated"`
Version int64 `db:"build_version" json:"version"`
Stages []*Stage `db:"-" json:"stages,omitempty"`
}
// BuildStore defines operations for working with builds.
type BuildStore interface {
// Find returns a build from the datastore.
Find(context.Context, int64) (*Build, error)
// FindNumber returns a build from the datastore by build number.
FindNumber(context.Context, int64, int64) (*Build, error)
// FindLast returns the last build from the datastore by ref.
FindRef(context.Context, int64, string) (*Build, error)
// List returns a list of builds from the datastore by repository id.
List(context.Context, int64, int, int) ([]*Build, error)
// ListRef returns a list of builds from the datastore by ref.
ListRef(context.Context, int64, string, int, int) ([]*Build, error)
// LatestBranches returns the latest builds from the
// datastore by branch.
LatestBranches(context.Context, int64) ([]*Build, error)
// LatestPulls returns the latest builds from the
// datastore by pull request.
LatestPulls(context.Context, int64) ([]*Build, error)
// LatestDeploys returns the latest builds from the
// datastore by deployment target.
LatestDeploys(context.Context, int64) ([]*Build, error)
// Pending returns a list of pending builds from the
// datastore by repository id (DEPRECATED).
Pending(context.Context) ([]*Build, error)
// Running returns a list of running builds from the
// datastore by repository id (DEPRECATED).
Running(context.Context) ([]*Build, error)
// Create persists a build to the datastore.
Create(context.Context, *Build, []*Stage) error
// Update updates a build in the datastore.
Update(context.Context, *Build) error
// Delete deletes a build from the datastore.
Delete(context.Context, *Build) error
// DeletePull deletes a pull request index from the datastore.
DeletePull(context.Context, int64, int) error
// DeleteBranch deletes a branch index from the datastore.
DeleteBranch(context.Context, int64, string) error
// DeleteDeploy deletes a deploy index from the datastore.
DeleteDeploy(context.Context, int64, string) error
// Purge deletes builds from the database where the build number is less than n.
Purge(context.Context, int64, int64) error
// Count returns a count of builds.
Count(context.Context) (int64, error)
}
// IsDone returns true if the build has a completed state.
func (b *Build) IsDone() bool {
switch b.Status {
case StatusWaiting,
StatusPending,
StatusRunning,
StatusBlocked:
return false
default:
return true
}
}
// IsFailed returns true if the build has failed
func (b *Build) IsFailed() bool {
switch b.Status {
case StatusFailing,
StatusKilled,
StatusError:
return true
default:
return false
}
}

View File

@ -1,7 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.
// +build !oss
package core

View File

@ -1,27 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
// Canceler cancels a build.
type Canceler interface {
// Cancel cancels the provided build.
Cancel(context.Context, *Repository, *Build) error
// CancelPending cancels all pending builds of the same
// type of as the provided build.
CancelPending(context.Context, *Repository, *Build) error
}

View File

@ -1,41 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"encoding/json"
"io"
)
type CardInput struct {
Schema string `json:"schema"`
Data json.RawMessage `json:"data"`
}
// CardStore manages repository cards.
type CardStore interface {
// Find returns a card data stream from the datastore.
Find(ctx context.Context, step int64) (io.ReadCloser, error)
// Create copies the card stream from Reader r to the datastore.
Create(ctx context.Context, step int64, r io.Reader) error
// Update copies the card stream from Reader r to the datastore.
Update(ctx context.Context, step int64, r io.Reader) error
// Delete purges the card data from the datastore.
Delete(ctx context.Context, step int64) error
}

View File

@ -1,59 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
type (
// Commit represents a git commit.
Commit struct {
Sha string
Ref string
Message string
Author *Committer
Committer *Committer
Link string
}
// Committer represents the commit author.
Committer struct {
Name string
Email string
Date int64
Login string
Avatar string
}
// Change represents a file change in a commit.
Change struct {
Path string
Added bool
Renamed bool
Deleted bool
}
// CommitService provides access to the commit history from
// the external source code management service (e.g. GitHub).
CommitService interface {
// Find returns the commit information by sha.
Find(ctx context.Context, user *User, repo, sha string) (*Commit, error)
// FindRef returns the commit information by reference.
FindRef(ctx context.Context, user *User, repo, ref string) (*Commit, error)
// ListChanges returns the files change by sha or reference.
ListChanges(ctx context.Context, user *User, repo, sha, ref string) ([]*Change, error)
}
)

View File

@ -1,40 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
type (
// Config represents a pipeline config file.
Config struct {
Data string `json:"data"`
Kind string `json:"kind"`
}
// ConfigArgs represents a request for the pipeline
// configuration file (e.g. .drone.yml)
ConfigArgs struct {
User *User `json:"-"`
Repo *Repository `json:"repo,omitempty"`
Build *Build `json:"build,omitempty"`
Config *Config `json:"config,omitempty"`
}
// ConfigService provides pipeline configuration from an
// external service.
ConfigService interface {
Find(context.Context, *ConfigArgs) (*Config, error)
}
)

View File

@ -1,35 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
type (
// ConvertArgs represents a request to the pipeline
// conversion service.
ConvertArgs struct {
User *User `json:"-"`
Repo *Repository `json:"repo,omitempty"`
Build *Build `json:"build,omitempty"`
Config *Config `json:"config,omitempty"`
}
// ConvertService converts non-native pipeline
// configuration formats to native configuration
// formats (e.g. jsonnet to yaml).
ConvertService interface {
Convert(context.Context, *ConvertArgs) (*Config, error)
}
)

View File

@ -1,117 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"errors"
"time"
"github.com/gosimple/slug"
"github.com/robfig/cron"
)
var (
errCronExprInvalid = errors.New("Invalid Cronjob Expression")
errCronNameInvalid = errors.New("Invalid Cronjob Name")
errCronBranchInvalid = errors.New("Invalid Cronjob Branch")
)
type (
// Cron defines a cron job.
Cron struct {
ID int64 `json:"id"`
RepoID int64 `json:"repo_id"`
Name string `json:"name"`
Expr string `json:"expr"`
Next int64 `json:"next"`
Prev int64 `json:"prev"`
Event string `json:"event"`
Branch string `json:"branch"`
Target string `json:"target,omitempty"`
Disabled bool `json:"disabled"`
Created int64 `json:"created"`
Updated int64 `json:"updated"`
Version int64 `json:"version"`
}
// CronStore persists cron information to storage.
CronStore interface {
// List returns a cron list from the datastore.
List(context.Context, int64) ([]*Cron, error)
// Ready returns a cron list from the datastore ready for execution.
Ready(context.Context, int64) ([]*Cron, error)
// Find returns a cron job from the datastore.
Find(context.Context, int64) (*Cron, error)
// FindName returns a cron job from the datastore.
FindName(context.Context, int64, string) (*Cron, error)
// Create persists a new cron job to the datastore.
Create(context.Context, *Cron) error
// Update persists an updated cron job to the datastore.
Update(context.Context, *Cron) error
// Delete deletes a cron job from the datastore.
Delete(context.Context, *Cron) error
}
)
// Validate validates the required fields and formats.
func (c *Cron) Validate() error {
_, err := cron.Parse(c.Expr)
if err != nil {
return errCronExprInvalid
}
switch {
case c.Name == "":
return errCronNameInvalid
case c.Name != slug.Make(c.Name):
return errCronNameInvalid
case c.Branch == "":
return errCronBranchInvalid
default:
return nil
}
}
// SetExpr sets the cron expression name and updates
// the next execution date.
func (c *Cron) SetExpr(expr string) error {
_, err := cron.Parse(expr)
if err != nil {
return errCronExprInvalid
}
c.Expr = expr
return c.Update()
}
// SetName sets the cronjob name.
func (c *Cron) SetName(name string) {
c.Name = slug.Make(name)
}
// Update updates the next Cron execution date.
func (c *Cron) Update() error {
sched, err := cron.Parse(c.Expr)
if err != nil {
return err
}
c.Next = sched.Next(time.Now()).Unix()
return nil
}

View File

@ -1,7 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.
// +build !oss
package core

View File

@ -1,26 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
// Hook event constants.
const (
EventCron = "cron"
EventCustom = "custom"
EventPush = "push"
EventPullRequest = "pull_request"
EventTag = "tag"
EventPromote = "promote"
EventRollback = "rollback"
)

View File

@ -1,40 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
type (
// File represents the raw file contents in the remote
// version control system.
File struct {
Data []byte
Hash []byte
}
// FileArgs provides repository and commit details required
// to fetch the file from the remote source code management
// service.
FileArgs struct {
Commit string
Ref string
}
// FileService provides access to contents of files in
// the remote source code management service (e.g. GitHub).
FileService interface {
Find(ctx context.Context, user *User, repo, commit, ref, path string) (*File, error)
}
)

View File

@ -1,70 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"net/http"
)
// Hook action constants.
const (
ActionOpen = "open"
ActionClose = "close"
ActionCreate = "create"
ActionDelete = "delete"
ActionSync = "sync"
)
// Hook represents the payload of a post-commit hook.
type Hook struct {
Parent int64 `json:"parent"`
Trigger string `json:"trigger"`
Event string `json:"event"`
Action string `json:"action"`
Link string `json:"link"`
Timestamp int64 `json:"timestamp"`
Title string `json:"title"`
Message string `json:"message"`
Before string `json:"before"`
After string `json:"after"`
Ref string `json:"ref"`
Fork string `json:"hook"`
Source string `json:"source"`
Target string `json:"target"`
Author string `json:"author_login"`
AuthorName string `json:"author_name"`
AuthorEmail string `json:"author_email"`
AuthorAvatar string `json:"author_avatar"`
Deployment string `json:"deploy_to"`
DeploymentID int64 `json:"deploy_id"`
Debug bool `json:"debug"`
Cron string `json:"cron"`
Sender string `json:"sender"`
Params map[string]string `json:"params"`
}
// HookService manages post-commit hooks in the external
// source code management service (e.g. GitHub).
type HookService interface {
Create(ctx context.Context, user *User, repo *Repository) error
Delete(ctx context.Context, user *User, repo *Repository) error
}
// HookParser parses a post-commit hook from the source
// code management system, and returns normalized data.
type HookParser interface {
Parse(req *http.Request, secretFunc func(string) string) (*Hook, *Repository, error)
}

View File

@ -1,7 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.
// +build !oss
package core

View File

@ -1,75 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"errors"
"time"
)
// License types.
const (
LicenseFoss = "foss"
LicenseFree = "free"
LicensePersonal = "personal"
LicenseStandard = "standard"
LicenseTrial = "trial"
)
// ErrUserLimit is returned when attempting to create a new
// user but the maximum number of allowed user accounts
// is exceeded.
var ErrUserLimit = errors.New("User limit exceeded")
// ErrRepoLimit is returned when attempting to create a new
// repository but the maximum number of allowed repositories
// is exceeded.
var ErrRepoLimit = errors.New("Repository limit exceeded")
// ErrBuildLimit is returned when attempting to create a new
// build but the maximum number of allowed builds is exceeded.
var ErrBuildLimit = errors.New("Build limit exceeded")
type (
// License defines software license parameters.
License struct {
Licensor string `json:"-"`
Subscription string `json:"-"`
Expires time.Time `json:"expires_at,omitempty"`
Kind string `json:"kind,omitempty"`
Repos int64 `json:"repos,omitempty"`
Users int64 `json:"users,omitempty"`
Builds int64 `json:"builds,omitempty"`
Nodes int64 `json:"nodes,omitempty"`
}
// LicenseService provides access to the license
// service and can be used to check for violations
// and expirations.
LicenseService interface {
// Exceeded returns true if the system has exceeded
// its limits as defined in the license.
Exceeded(context.Context) (bool, error)
// Expired returns true if the license is expired.
Expired(context.Context) bool
}
)
// Expired returns true if the license is expired.
func (l *License) Expired() bool {
return l.Expires.IsZero() == false && time.Now().After(l.Expires)
}

View File

@ -1,7 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Drone Non-Commercial License
// that can be found in the LICENSE file.
// +build !oss
package core

View File

@ -1,23 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import "context"
// Linker provides a deep link to a git resource in the
// source control management system for a given build.
type Linker interface {
Link(ctx context.Context, repo, ref, sha string) (string, error)
}

View File

@ -1,70 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"io"
)
// Line represents a line in the logs.
type Line struct {
Number int `json:"pos"`
Message string `json:"out"`
Timestamp int64 `json:"time"`
}
// LogStore persists build output to storage.
type LogStore interface {
// Find returns a log stream from the datastore.
Find(ctx context.Context, stage int64) (io.ReadCloser, error)
// Create writes copies the log stream from Reader r to the datastore.
Create(ctx context.Context, stage int64, r io.Reader) error
// Update writes copies the log stream from Reader r to the datastore.
Update(ctx context.Context, stage int64, r io.Reader) error
// Delete purges the log stream from the datastore.
Delete(ctx context.Context, stage int64) error
}
// LogStream manages a live stream of logs.
type LogStream interface {
// Create creates the log stream for the step ID.
Create(context.Context, int64) error
// Delete deletes the log stream for the step ID.
Delete(context.Context, int64) error
// Writes writes to the log stream.
Write(context.Context, int64, *Line) error
// Tail tails the log stream.
Tail(context.Context, int64) (<-chan *Line, <-chan error)
// Info returns internal stream information.
Info(context.Context) *LogStreamInfo
}
// LogStreamInfo provides internal stream information. This can
// be used to monitor the number of registered streams and
// subscribers.
type LogStreamInfo struct {
// Streams is a key-value pair where the key is the step
// identifier, and the value is the count of subscribers
// streaming the logs.
Streams map[int64]int `json:"streams"`
}

View File

@ -1,58 +0,0 @@
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package core
import (
"context"
"fmt"
"net/url"
)
type (
// Netrc contains login and initialization information used by
// an automated login process.
Netrc struct {
Machine string `json:"machine"`
Login string `json:"login"`
Password string `json:"password"`
}
// NetrcService returns a valid netrc file that can be used
// to authenticate and clone a private repository. If
// authentication is not required or enabled, a nil Netrc
// file and nil error are returned.
NetrcService interface {
Create(context.Context, *User, *Repository) (*Netrc, error)
}
)
// SetMachine sets the netrc machine from a URL value.
func (n *Netrc) SetMachine(address string) error {
url, err := url.Parse(address)
if err != nil {
return err
}
n.Machine = url.Hostname()
return nil
}
// String returns the string representation of a netrc file.
func (n *Netrc) String() string {
return fmt.Sprintf("machine %s login %s password %s",
n.Machine,
n.Login,
n.Password,
)
}

Some files were not shown because too many files have changed in this diff Show More