Merge pull request #59 from MbolotSuse/ver-upd-pipeline

Steve Pipeline, Go Version updates
This commit is contained in:
Michael Bolot 2022-10-27 16:22:34 -05:00 committed by GitHub
commit 44e5b8dc3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 246 additions and 49 deletions

View File

@ -8,6 +8,51 @@ steps:
settings:
api_key:
from_secret: FOSSA_API_KEY
when:
instance:
include:
- drone-publish.rancher.io
exclude:
- drone-pr.rancher.io
---
kind: pipeline
name: build
steps:
- name: build
image: registry.suse.com/bci/golang:1.19
commands:
- make build-bin
when:
instance:
- drone-publish.rancher.io
event:
- push
- pull_request
---
kind: pipeline
name: validate
steps:
- name: validate
image: registry.suse.com/bci/bci-base:15.4
commands:
- zypper in -y go=1.19 git tar gzip make
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.49.0
- mv ./bin/golangci-lint /usr/local/bin/golangci-lint
- make validate
when:
event:
- push
- pull_request
---
kind: pipeline
name: test
steps:
- name: test
image: registry.suse.com/bci/golang:1.19
commands:
- make test
when:
event:
- push
- pull_request

67
.golangci.json Normal file
View File

@ -0,0 +1,67 @@
{
"linters": {
"disable-all": true,
"enable": [
"govet",
"revive",
"goimports",
"misspell",
"ineffassign",
"gofmt"
]
},
"linters-settings": {
"govet": {
"check-shadowing": false
},
"gofmt": {
"simplify": false
}
},
"run": {
"skip-dirs": [
"vendor",
"tests",
"pkg/client",
"pkg/generated"
],
"tests": false,
"timeout": "10m"
},
"issues": {
"exclude-rules": [
{
"linters": "govet",
"text": "^(nilness|structtag)"
},
{
"path":"pkg/apis/management.cattle.io/v3/globaldns_types.go",
"text":".*lobalDns.*"
},
{
"path": "pkg/apis/management.cattle.io/v3/zz_generated_register.go",
"text":".*lobalDns.*"
},
{
"path":"pkg/apis/management.cattle.io/v3/zz_generated_list_types.go",
"text":".*lobalDns.*"
},
{
"linters": "revive",
"text": "should have comment"
},
{
"linters": "revive",
"text": "should be of the form"
},
{
"linters": "revive",
"text": "by other packages, and that stutters"
},
{
"linters": "typecheck",
"text": "imported but not used as apierrors"
}
]
}
}

View File

@ -1,5 +1,5 @@
# syntax = docker/dockerfile:experimental
FROM golang:1.13.4 as build
FROM registry.suse.com/bci/golang:1.19 as build
COPY go.mod go.sum main.go /src/
COPY pkg /src/pkg/
#RUN --mount=type=cache,target=/root/.cache/go-build \
@ -7,8 +7,7 @@ RUN \
cd /src && \
CGO_ENABLED=0 go build -ldflags "-extldflags -static -s" -o /steve
FROM alpine
RUN apk -U --no-cache add ca-certificates
FROM registry.suse.com/bci/bci-micro:15.4.15.1
COPY --from=build /steve /usr/bin/steve
# Hack to make golang do files,dns search order
ENV LOCALDOMAIN=""

View File

@ -1,8 +1,17 @@
build:
docker build -t steve .
build-bin:
bash scripts/build-bin.sh
run: build
docker run $(DOCKER_ARGS) --rm -p 8989:9080 -it -v ${HOME}/.kube:/root/.kube steve --https-listen-port 0
run-host: build
docker run $(DOCKER_ARGS) --net=host --uts=host --rm -it -v ${HOME}/.kube:/root/.kube steve --kubeconfig /root/.kube/config --http-listen-port 8989 --https-listen-port 0
test:
bash scripts/test.sh
validate:
bash scripts/validate.sh

76
go.mod
View File

@ -1,6 +1,6 @@
module github.com/rancher/steve
go 1.13
go 1.19
replace (
github.com/crewjam/saml => github.com/rancher/saml v0.0.0-20180713225824-ce1532152fde
@ -14,7 +14,6 @@ require (
github.com/adrg/xdg v0.3.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2
github.com/imdario/mergo v0.3.8 // indirect
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.1
@ -38,3 +37,76 @@ require (
k8s.io/kube-aggregator v0.24.0
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42
)
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/imdario/mergo v0.3.8 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.opentelemetry.io/contrib v0.20.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0 // indirect
go.opentelemetry.io/otel v0.20.0 // indirect
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
go.opentelemetry.io/otel/metric v0.20.0 // indirect
go.opentelemetry.io/otel/sdk v0.20.0 // indirect
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
go.opentelemetry.io/otel/trace v0.20.0 // indirect
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect
google.golang.org/grpc v1.40.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/component-base v0.24.0 // indirect
k8s.io/klog/v2 v2.60.1 // indirect
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect
sigs.k8s.io/cli-utils v0.16.0 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)

6
go.sum
View File

@ -89,14 +89,12 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
@ -129,7 +127,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -590,7 +587,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uY
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@ -787,7 +783,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1294,7 +1289,6 @@ sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5
sigs.k8s.io/kustomize/kyaml v0.4.0/go.mod h1:XJL84E6sOFeNrQ7CADiemc1B0EjIxHo3OhW4o1aJYNw=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=

View File

@ -1,12 +1,12 @@
package cli
import (
"k8s.io/client-go/tools/clientcmd"
"os"
"time"
"github.com/rancher/steve/pkg/auth"
"github.com/urfave/cli"
"k8s.io/client-go/tools/clientcmd"
)
type WebhookConfig struct {

View File

@ -2,7 +2,6 @@ package auth
import (
"io/ioutil"
"k8s.io/client-go/rest"
"net/http"
"strings"
"time"
@ -13,6 +12,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/plugin/pkg/authenticator/token/webhook"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/transport"

View File

@ -128,10 +128,10 @@ type PodOptions struct {
// CreatePod will create a pod with a service account that impersonates as user. Corresponding
// ClusterRoles, ClusterRoleBindings, and ServiceAccounts will be create.
// IMPORTANT NOTES:
// 1. To ensure this is used securely the namespace assigned to the pod must be a dedicated
// namespace used only for the purpose of running impersonated pods. This is to ensure
// proper protection for the service accounts created.
// 2. The pod must KUBECONFIG env var set to where you expect the kubeconfig to reside
// 1. To ensure this is used securely the namespace assigned to the pod must be a dedicated
// namespace used only for the purpose of running impersonated pods. This is to ensure
// proper protection for the service accounts created.
// 2. The pod must KUBECONFIG env var set to where you expect the kubeconfig to reside
func (s *PodImpersonation) CreatePod(ctx context.Context, user user.Info, pod *v1.Pod, podOptions *PodOptions) (*v1.Pod, error) {
if podOptions == nil {
podOptions = &PodOptions{}

View File

@ -280,7 +280,7 @@ func removeSummary(counts Summary, summary summary.Summary) Summary {
if counts.States == nil {
counts.States = map[string]int{}
}
counts.States[simpleState(summary)] -= 1
counts.States[simpleState(summary)]--
}
return counts
}
@ -297,7 +297,7 @@ func addSummary(counts Summary, summary summary.Summary) Summary {
if counts.States == nil {
counts.States = map[string]int{}
}
counts.States[simpleState(summary)] += 1
counts.States[simpleState(summary)]++
}
return counts
}

View File

@ -6,7 +6,7 @@ import (
"github.com/rancher/steve/pkg/schema/table"
apiextv1 "github.com/rancher/wrangler/pkg/generated/controllers/apiextensions.k8s.io/v1"
"github.com/rancher/wrangler/pkg/schemas"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

View File

@ -5,7 +5,7 @@ import (
"strings"
"github.com/rancher/apiserver/pkg/types"
"github.com/rancher/wrangler/pkg/generated/controllers/apiextensions.k8s.io/v1"
v1 "github.com/rancher/wrangler/pkg/generated/controllers/apiextensions.k8s.io/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
)

View File

@ -41,11 +41,11 @@ func (c *Collection) Schemas(user user.Info) (*types.APISchemas, error) {
func (c *Collection) removeOldRecords(access *accesscontrol.AccessSet, user user.Info) {
current, ok := c.userCache.Get(user.GetName())
if ok {
currentId, cOk := current.(string)
if cOk && currentId != access.ID {
currentID, cOk := current.(string)
if cOk && currentID != access.ID {
// we only want to keep around one record per user. If our current access record is invalid, purge the
//record of it from the cache, so we don't keep duplicates
c.purgeUserRecords(currentId)
c.purgeUserRecords(currentID)
c.userCache.Remove(user.GetName())
}
}

View File

@ -9,11 +9,6 @@ import (
func k8sAPI(sf schema.Factory, apiOp *types.APIRequest) {
vars := mux.Vars(apiOp.Request)
group := vars["group"]
if group == "core" {
group = ""
}
apiOp.Name = vars["name"]
apiOp.Type = vars["type"]

View File

@ -63,4 +63,4 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.APISchema, w types.
apiEvent, err := s.Store.Watch(apiOp, schema, w)
m.RecordProxyStoreResponseTime(err, float64(time.Since(storeStart).Milliseconds()))
return apiEvent, err
}
}

View File

@ -170,17 +170,16 @@ func (p *ParallelPartitionLister) feeder(ctx context.Context, state listState, l
}
capacity = 0
return nil
} else {
result <- list.Objects
capacity -= len(list.Objects)
if list.Continue == "" {
return nil
}
// loop again and get more data
state.Continue = list.Continue
state.PartitionName = partition.Name()
state.Offset = 0
}
result <- list.Objects
capacity -= len(list.Objects)
if list.Continue == "" {
return nil
}
// loop again and get more data
state.Continue = list.Continue
state.PartitionName = partition.Name()
state.Offset = 0
}
})
}

View File

@ -166,14 +166,13 @@ func isPassthroughUnconstrained(apiOp *types.APIRequest, schema *types.APISchema
if apiOp.Namespace != "" {
if resources[apiOp.Namespace].All {
return nil, true
} else {
return []partition.Partition{
Partition{
Namespace: apiOp.Namespace,
Names: resources[apiOp.Namespace].Names,
},
}, false
}
return []partition.Partition{
Partition{
Namespace: apiOp.Namespace,
Names: resources[apiOp.Namespace].Names,
},
}, false
}
var result []partition.Partition

3
scripts/build-bin.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
CGO_ENABLED=0 go build -ldflags "-extldflags -static -s" -o ./bin/steve

3
scripts/test.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
go test ./...

12
scripts/validate.sh Normal file
View File

@ -0,0 +1,12 @@
#!/bin/bash
set -e
golangci-lint run
go mod tidy
go mod verify
unclean=$(git status --porcelain --untracked-files=no)
if [ -n "$unclean" ]; then
echo "Encountered dirty repo!";
echo "$unclean";
exit 1;
fi