Merge branch 'dev-v3' into fix/updateCobraForCompletion

Signed-off-by: Marc Khouzam <marc.khouzam@ville.montreal.qc.ca>
pull/5655/head
Marc Khouzam 6 years ago
commit 1af6d08c27

212
Gopkg.lock generated

@ -29,7 +29,7 @@
revision = "d6e3b3328b783f23731bc4d058875b0371ff8109" revision = "d6e3b3328b783f23731bc4d058875b0371ff8109"
[[projects]] [[projects]]
digest = "1:11e17f77281a8ab1267c30ca114e934f93e63379d328615b3d3448f0c87f7dc9" digest = "1:1cd7c78615a24f1f886b7c23d9a1d323dee3c36e76c0a64a348ab72036be90bf"
name = "github.com/Azure/go-autorest" name = "github.com/Azure/go-autorest"
packages = [ packages = [
"autorest", "autorest",
@ -44,7 +44,7 @@
version = "v11.2.8" version = "v11.2.8"
[[projects]] [[projects]]
digest = "1:d9b9f8e552b21361f2753af22b298440b06287e6390e7f33f010f27a62d90179" digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
name = "github.com/BurntSushi/toml" name = "github.com/BurntSushi/toml"
packages = ["."] packages = ["."]
pruneopts = "UT" pruneopts = "UT"
@ -91,6 +91,22 @@
revision = "b4f55832432b95a611cf1495272b5c8e24952a1a" revision = "b4f55832432b95a611cf1495272b5c8e24952a1a"
version = "v1.13.0" version = "v1.13.0"
[[projects]]
digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892"
name = "github.com/Microsoft/go-winio"
packages = ["."]
pruneopts = "UT"
revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8"
version = "v0.4.12"
[[projects]]
branch = "master"
digest = "1:3721a10686511b80c052323423f0de17a8c06d417dbdd3b392b1578432a33aae"
name = "github.com/Nvveen/Gotty"
packages = ["."]
pruneopts = "UT"
revision = "cd527374f1e5bff4938207604a14f2e38a9cf512"
[[projects]] [[projects]]
digest = "1:d1665c44bd5db19aaee18d1b6233c99b0b9a986e8bccb24ef54747547a48027f" digest = "1:d1665c44bd5db19aaee18d1b6233c99b0b9a986e8bccb24ef54747547a48027f"
name = "github.com/PuerkitoBio/purell" name = "github.com/PuerkitoBio/purell"
@ -140,7 +156,7 @@
version = "v0.4.1" version = "v0.4.1"
[[projects]] [[projects]]
digest = "1:0a896acf6dcc0f0228090208b69e70ea681843771c07d5990b6c495baa5f9d91" digest = "1:a9ef0c82c0459e56e52a374cff03bc7b21a2e76bd957cc368fafd23ca0ba0b45"
name = "github.com/bugsnag/bugsnag-go" name = "github.com/bugsnag/bugsnag-go"
packages = [ packages = [
".", ".",
@ -159,7 +175,7 @@
version = "v1.2.0" version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:7b69ec1477f4beff10335b7da13a3c0329dfdb3141c5653a249760d1ee177a7c" digest = "1:65b0d980b428a6ad4425f2df4cd5410edd81f044cf527bd1c345368444649e58"
name = "github.com/census-instrumentation/opencensus-proto" name = "github.com/census-instrumentation/opencensus-proto"
packages = [ packages = [
"gen-go/agent/common/v1", "gen-go/agent/common/v1",
@ -173,7 +189,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:1f8ed389b3f7923ed00486d86509f8f859a7b2dcffb5f2f137c7150ddca66dbb" digest = "1:95e08278c876d185ba67533f045e9e63b3c9d02cbd60beb0f4dbaa2344a13ac2"
name = "github.com/chai2010/gettext-go" name = "github.com/chai2010/gettext-go"
packages = [ packages = [
"gettext", "gettext",
@ -185,7 +201,7 @@
revision = "bf70f2a70fb1b1f36d90d671a72795984eab0fcb" revision = "bf70f2a70fb1b1f36d90d671a72795984eab0fcb"
[[projects]] [[projects]]
digest = "1:6248c3bfae5a941cbeb291dac75fb633ca0b18af62c69c6b0ec6b40d7a4844cc" digest = "1:37f8940c4d3c41536ea882b1ca3498e403c04892dfc34bd0d670ed9eafccda9a"
name = "github.com/containerd/containerd" name = "github.com/containerd/containerd"
packages = [ packages = [
"content", "content",
@ -198,8 +214,16 @@
"remotes/docker", "remotes/docker",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "9b32062dc1f5a7c2564315c269b5059754f12b9d" revision = "894b81a4b802e4eb2a91d1ce216b8817763c29fb"
version = "v1.2.1" version = "v1.2.6"
[[projects]]
branch = "master"
digest = "1:e48c63e818c67fbf3d7afe20bba33134ab1a5bf384847385384fd027652a5a96"
name = "github.com/containerd/continuity"
packages = ["pathdriver"]
pruneopts = "UT"
revision = "004b46473808b3e7a4a3049c20e4376c91eb966d"
[[projects]] [[projects]]
digest = "1:7cb4fdca4c251b3ef8027c90ea35f70c7b661a593b9eeae34753c65499098bb1" digest = "1:7cb4fdca4c251b3ef8027c90ea35f70c7b661a593b9eeae34753c65499098bb1"
@ -218,15 +242,17 @@
version = "v1.1.1" version = "v1.1.1"
[[projects]] [[projects]]
digest = "1:c2b304e9f010d2fdd048b50c8c9eaa3ae947e7c5717be87a379f63980786dcb8" digest = "1:82158435e282da9b23bb1188487fe1c68b17a54ed9dcd557ab6204782ad3ff92"
name = "github.com/deislabs/oras" name = "github.com/deislabs/oras"
packages = [ packages = [
"pkg/auth",
"pkg/auth/docker",
"pkg/content", "pkg/content",
"pkg/oras", "pkg/oras",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "e8a1fa6ff9a507b99eedd45745959e8c5b826d9f" revision = "9f7669048990b0d0c186985737e6a6c3bb3f7ecc"
version = "v0.3.3" version = "v0.4.0"
[[projects]] [[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55" digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
@ -237,7 +263,20 @@
version = "v3.2.0" version = "v3.2.0"
[[projects]] [[projects]]
digest = "1:ef764aa16c439ecf65aa588d21ad3499c55064f7ea05082b18211468d2ca99be" digest = "1:f65090e4f60dcd4d2de69e8ebca022d59a8c6463a3a4c122e64cec91a83749ff"
name = "github.com/docker/cli"
packages = [
"cli/config",
"cli/config/configfile",
"cli/config/credentials",
"opts",
]
pruneopts = "UT"
revision = "c89750f836c57ce10386e71669e1b08a54c3caeb"
version = "v18.09.5"
[[projects]]
digest = "1:feaf11ab67fe48ec2712bf9d44e2fb2d4ebdc5da8e5a47bd3ce05bae9f82825b"
name = "github.com/docker/distribution" name = "github.com/docker/distribution"
packages = [ packages = [
".", ".",
@ -258,6 +297,7 @@
"registry/api/errcode", "registry/api/errcode",
"registry/api/v2", "registry/api/v2",
"registry/auth", "registry/auth",
"registry/auth/htpasswd",
"registry/client", "registry/client",
"registry/client/auth", "registry/client/auth",
"registry/client/auth/challenge", "registry/client/auth/challenge",
@ -286,15 +326,61 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:efacbb3ab555c719a041fb74373aa9a6c46c2579f0bfb9fae9e6c9daf662a4eb" digest = "1:b5be0d9940d8fa3ff7df4949a8e8c47a7f93ea8251239ad074e1a6b0db55876a"
name = "github.com/docker/docker" name = "github.com/docker/docker"
packages = [ packages = [
"api/types",
"api/types/blkiodev",
"api/types/container",
"api/types/filters",
"api/types/mount",
"api/types/network",
"api/types/registry",
"api/types/strslice",
"api/types/swarm",
"api/types/swarm/runtime",
"api/types/versions",
"errdefs",
"pkg/homedir",
"pkg/idtools",
"pkg/ioutils",
"pkg/jsonmessage",
"pkg/longpath",
"pkg/mount",
"pkg/stringid",
"pkg/system",
"pkg/tarsum",
"pkg/term", "pkg/term",
"pkg/term/windows", "pkg/term/windows",
"registry",
"registry/resumable",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "2cb26cfe9cbf8a64c5046c74d65f4528b22e67f4" revision = "2cb26cfe9cbf8a64c5046c74d65f4528b22e67f4"
[[projects]]
digest = "1:8866486038791fe65ea1abf660041423954b1f3fb99ea6a0ad8424422e943458"
name = "github.com/docker/docker-credential-helpers"
packages = [
"client",
"credentials",
]
pruneopts = "UT"
revision = "5241b46610f2491efdf9d1c85f1ddf5b02f6d962"
version = "v0.6.1"
[[projects]]
digest = "1:811c86996b1ca46729bad2724d4499014c4b9effd05ef8c71b852aad90deb0ce"
name = "github.com/docker/go-connections"
packages = [
"nat",
"sockets",
"tlsconfig",
]
pruneopts = "UT"
revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55"
version = "v0.4.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:2b126e77be4ab4b92cdb3924c87894dd76bf365ba282f358a13133e848aa0059" digest = "1:2b126e77be4ab4b92cdb3924c87894dd76bf365ba282f358a13133e848aa0059"
@ -321,7 +407,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:93a21c82477de8936e5e238bc8f98a1fee607241326abbc812d7e5d5d8649d6b" digest = "1:ecdc8e0fe3bc7d549af1c9c36acf3820523b707d6c071b6d0c3860882c6f7b42"
name = "github.com/docker/spdystream" name = "github.com/docker/spdystream"
packages = [ packages = [
".", ".",
@ -331,7 +417,7 @@
revision = "6480d4af844c189cf5dd913db24ddd339d3a4f85" revision = "6480d4af844c189cf5dd913db24ddd339d3a4f85"
[[projects]] [[projects]]
digest = "1:513bf2fb3b6a767c5679569d4b54b2cc634fd7e5df542b4637363189699b1b81" digest = "1:899234af23e5793c34e06fd397f86ba33af5307b959b6a7afd19b63db065a9d7"
name = "github.com/emicklei/go-restful" name = "github.com/emicklei/go-restful"
packages = [ packages = [
".", ".",
@ -366,7 +452,7 @@
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:f26133af0db0007ccbd4830a033f7124c38cbab8afecd06452f17c6b7fd4c3a9" digest = "1:0594af97b2f4cec6554086eeace6597e20a4b69466eb4ada25adf9f4300dddd2"
name = "github.com/garyburd/redigo" name = "github.com/garyburd/redigo"
packages = [ packages = [
"internal", "internal",
@ -417,7 +503,7 @@
version = "v0.17.2" version = "v0.17.2"
[[projects]] [[projects]]
digest = "1:f50cd3eefda65d741da69224fbfba0d7fea9847bad9b4f462457bae567b198f2" digest = "1:9ae31ce33b4bab257668963e844d98765b44160be4ee98cafc44637a213e530d"
name = "github.com/gobwas/glob" name = "github.com/gobwas/glob"
packages = [ packages = [
".", ".",
@ -434,7 +520,7 @@
version = "v0.2.3" version = "v0.2.3"
[[projects]] [[projects]]
digest = "1:3eb221925fcc7f9dcf507ecc2510bf011a1b5abf2869c8da523f72faf85fbbe9" digest = "1:b402bb9a24d108a9405a6f34675091b036c8b056aac843bf6ef2389a65c5cf48"
name = "github.com/gogo/protobuf" name = "github.com/gogo/protobuf"
packages = [ packages = [
"proto", "proto",
@ -453,7 +539,7 @@
revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa"
[[projects]] [[projects]]
digest = "1:92a1b6546eab24700568ef2821fd42fccc527361056bbb70837442e14aa32f12" digest = "1:8f0705fa33e8957018611cc81c65cb373b626c092d39931bb86882489fc4c3f4"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
@ -492,7 +578,7 @@
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
digest = "1:a6a3cf96c8f626d50c11f5ab6c6a92e3ccde777aafe091dd305224c85d3c0030" digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
name = "github.com/googleapis/gnostic" name = "github.com/googleapis/gnostic"
packages = [ packages = [
"OpenAPIv2", "OpenAPIv2",
@ -505,7 +591,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:2d2da032a134b161abb9cbc826fda2c7501fb921662bb9234d5273b711c04a7f" digest = "1:d47549022c929925679aec031329f59f250d704f69ee44a194998cdb8d873393"
name = "github.com/gophercloud/gophercloud" name = "github.com/gophercloud/gophercloud"
packages = [ packages = [
".", ".",
@ -537,7 +623,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:cfff48546cb55d9bfcb60078c1bb27b0cb8fbf403d8d481d7244a920359c8d7b" digest = "1:4e08dc2383a46b3107f0b34ca338c4459e8fc8ee90e46a60e728aa8a2b21d558"
name = "github.com/gosuri/uitable" name = "github.com/gosuri/uitable"
packages = [ packages = [
".", ".",
@ -549,7 +635,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:d9221e54176cdc408f6cb9cc35626743e8728fd7e69e5b0df075df15e4bec895" digest = "1:86c1210529e69d69860f2bb3ee9ccce0b595aa3f9165e7dd1388e5c612915888"
name = "github.com/gregjones/httpcache" name = "github.com/gregjones/httpcache"
packages = [ packages = [
".", ".",
@ -627,7 +713,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:ebd709f6c64e850ee37ffd662604b647934ba1b7da39c7ba26381d634a4b6d4d" digest = "1:84a5a2b67486d5d67060ac393aa255d05d24ed5ee41daecd5635ec22657b6492"
name = "github.com/mailru/easyjson" name = "github.com/mailru/easyjson"
packages = [ packages = [
"buffer", "buffer",
@ -701,7 +787,7 @@
version = "v1.0.0-rc1" version = "v1.0.0-rc1"
[[projects]] [[projects]]
digest = "1:7c5c09ec84d18b0dc5ec0de36c1b8d12d3bf1815d04b90dc50ab082f3b8f13f1" digest = "1:11db38d694c130c800d0aefb502fb02519e514dc53d9804ce51d1ad25ec27db6"
name = "github.com/opencontainers/image-spec" name = "github.com/opencontainers/image-spec"
packages = [ packages = [
"specs-go", "specs-go",
@ -711,6 +797,14 @@
revision = "d60099175f88c47cd379c4738d158884749ed235" revision = "d60099175f88c47cd379c4738d158884749ed235"
version = "v1.0.1" version = "v1.0.1"
[[projects]]
digest = "1:38ee335aedf4626620f3cf8f605661e71abdcce7b40b38921962beb3980f0a20"
name = "github.com/opencontainers/runc"
packages = ["libcontainer/user"]
pruneopts = "UT"
revision = "baf6536d6259209c3edfa2b22237af82942d3dfa"
version = "v0.1.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2" digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2"
@ -744,7 +838,7 @@
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:32c1cb4c09d4eb89294d52c2df910ad981aa8d47f06fee22f0112702cf5f4e53" digest = "1:93a746f1060a8acbcf69344862b2ceced80f854170e1caae089b2834c5fbf7f4"
name = "github.com/prometheus/client_golang" name = "github.com/prometheus/client_golang"
packages = [ packages = [
"prometheus", "prometheus",
@ -757,14 +851,14 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a" digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model" name = "github.com/prometheus/client_model"
packages = ["go"] packages = ["go"]
pruneopts = "UT" pruneopts = "UT"
revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8" revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8"
[[projects]] [[projects]]
digest = "1:404f5b09a91546084d2d791b7148df956e7ce42cd75414649ee20aefac288e51" digest = "1:35cf6bdf68db765988baa9c4f10cc5d7dda1126a54bd62e252dbcd0b1fc8da90"
name = "github.com/prometheus/common" name = "github.com/prometheus/common"
packages = [ packages = [
"expfmt", "expfmt",
@ -777,7 +871,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:66ab3a15e2472626455c057a3010b54b5ed1e5194517035e1b74d9a620c6bb6a" digest = "1:5833c61ebbd625a6bad8e5a1ada2b3e13710cf3272046953a2c8915340fe60a3"
name = "github.com/prometheus/procfs" name = "github.com/prometheus/procfs"
packages = [ packages = [
".", ".",
@ -805,15 +899,15 @@
version = "v1.2.0" version = "v1.2.0"
[[projects]] [[projects]]
branch = "master" digest = "1:e01b05ba901239c783dfe56450bcde607fc858908529868259c9a8765dc176d0"
digest = "1:bfa8819cf03174788453b572ddef4dfcd7d43fdcbc661c7aa9bd9d15852cdcd8"
name = "github.com/spf13/cobra" name = "github.com/spf13/cobra"
packages = [ packages = [
".", ".",
"doc", "doc",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "67fc4837d267bc9bfd6e47f77783fcc3dffc68de" revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[projects]] [[projects]]
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
@ -824,7 +918,7 @@
version = "v1.0.3" version = "v1.0.3"
[[projects]] [[projects]]
digest = "1:9b3581602b9ee17983e3db9a4695c57fe1143d86bfc1d98600d0f97749027593" digest = "1:8ff03ccc603abb0d7cce94d34b613f5f6251a9e1931eba1a3f9888a9029b055c"
name = "github.com/stretchr/testify" name = "github.com/stretchr/testify"
packages = [ packages = [
"assert", "assert",
@ -890,7 +984,7 @@
revision = "b21fdbd4370f3717f3bbd2bf41c223bc273068e6" revision = "b21fdbd4370f3717f3bbd2bf41c223bc273068e6"
[[projects]] [[projects]]
digest = "1:996e7a159bad6d51ceffbd64d17998356fbb5601dc6ed4a67d77ace392f9cdce" digest = "1:2ae8314c44cd413cfdb5b1df082b350116dd8d2fff973e62c01b285b7affd89e"
name = "go.opencensus.io" name = "go.opencensus.io"
packages = [ packages = [
".", ".",
@ -915,9 +1009,11 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:64c445cda3e93ef79c10f21aaef5908e3b330729f1e3ca2fb6cb728b9cc775b3" digest = "1:91e034b0c63a4c747c6e9dc8285f36dc5fe699a78d34de0a663895e52ff673dd"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = [ packages = [
"bcrypt",
"blowfish",
"cast5", "cast5",
"ed25519", "ed25519",
"ed25519/internal/edwards25519", "ed25519/internal/edwards25519",
@ -938,7 +1034,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:6492d22c047269b7c1000e7794efe28ade2f0e14ce4e89d38cd7a5d25cd31c07" digest = "1:80c256dfc14840e13293d6404b7774e497187bd15a53f943f99bfaef4bbb2e42"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"bpf", "bpf",
@ -950,9 +1046,11 @@
"idna", "idna",
"internal/iana", "internal/iana",
"internal/socket", "internal/socket",
"internal/socks",
"internal/timeseries", "internal/timeseries",
"ipv4", "ipv4",
"ipv6", "ipv6",
"proxy",
"publicsuffix", "publicsuffix",
"trace", "trace",
] ]
@ -961,7 +1059,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:45e8fd4fd9d1f254a2166bb2d837a34274a9e2b16c23ada2f1f03c421c8ef704" digest = "1:23443edff0740e348959763085df98400dcfd85528d7771bb0ce9f5f2754ff4a"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
packages = [ packages = [
".", ".",
@ -975,7 +1073,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:a4b267e58eba4f8efcf35d73d68e142126b0ce508c099d418f56a5f0179f59ef" digest = "1:04a5b0e4138f98eef79ce12a955a420ee358e9f787044cc3a553ac3c3ade997e"
name = "golang.org/x/sync" name = "golang.org/x/sync"
packages = [ packages = [
"errgroup", "errgroup",
@ -986,7 +1084,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:dc09916156071dc2a710631c3f726fc7b3d0dd4996ccddaad79042272f516c2f" digest = "1:3d5e79e10549fd9119cbefd614b6d351ef5bd0be2f2b103a4199788e784cbc68"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"unix", "unix",
@ -996,7 +1094,7 @@
revision = "b4a75ba826a64a70990f11a225237acd6ef35c9f" revision = "b4a75ba826a64a70990f11a225237acd6ef35c9f"
[[projects]] [[projects]]
digest = "1:8e06c0384eb063fd67edc3cbc0be213b7f88a88c2a851a904c4319aaa19e1224" digest = "1:28756bf526c1af662d24519f2fa7abca7237bebb06e3e02941b2b6e5b6ceb7b9"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"collate", "collate",
@ -1035,14 +1133,14 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:55afc21c324dec8966cef5e8e7f0d7662efa943e30dc4d2a8e1699824c8fce5c" digest = "1:5f003878aabe31d7f6b842d4de32b41c46c214bb629bb485387dbcce1edf5643"
name = "google.golang.org/api" name = "google.golang.org/api"
packages = ["support/bundler"] packages = ["support/bundler"]
pruneopts = "UT" pruneopts = "UT"
revision = "65a46cafb132eff435c7d1e0f439cc73c8eebb85" revision = "65a46cafb132eff435c7d1e0f439cc73c8eebb85"
[[projects]] [[projects]]
digest = "1:0b4626f7673aa8961ae4d08df0d492a3d902e5f8356a1cab39ea598326c7f573" digest = "1:fa026a5c59bd2df343ec4a3538e6288dcf4e2ec5281d743ae82c120affe6926a"
name = "google.golang.org/appengine" name = "google.golang.org/appengine"
packages = [ packages = [
".", ".",
@ -1069,7 +1167,7 @@
revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2" revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2"
[[projects]] [[projects]]
digest = "1:851ba93ee00a247214f894bb3e85bb00d260a4e536e15539b2b2831a0405162f" digest = "1:9edd250a3c46675d0679d87540b30c9ed253b19bd1fd1af08f4f5fb3c79fc487"
name = "google.golang.org/grpc" name = "google.golang.org/grpc"
packages = [ packages = [
".", ".",
@ -1118,7 +1216,7 @@
version = "v0.9.1" version = "v0.9.1"
[[projects]] [[projects]]
digest = "1:bb0ec423b815fd5b98b33bfae448c77cbe4febe0b344deb8e5cd1ebbc15649a5" digest = "1:0c9d7630c981ff09c7d297db73b3a94358e6572e8de063853c38d1e2c500272e"
name = "gopkg.in/square/go-jose.v1" name = "gopkg.in/square/go-jose.v1"
packages = [ packages = [
".", ".",
@ -1131,7 +1229,7 @@
version = "v1.1.2" version = "v1.1.2"
[[projects]] [[projects]]
digest = "1:2290981a4c5f7bb9d1572fd0ef257fff17ee36d7c42bd5a69cdbdb3b753036dd" digest = "1:005cbf8b937fcb1694b9dbb845b0aef618627be7faf7bb330eb2490e3f506ef8"
name = "gopkg.in/square/go-jose.v2" name = "gopkg.in/square/go-jose.v2"
packages = [ packages = [
".", ".",
@ -1155,7 +1253,7 @@
[[projects]] [[projects]]
branch = "release-1.14" branch = "release-1.14"
digest = "1:afe9083e1570571e0d8639515b577c54fb838fe17ecf9cc23403de3209e5139d" digest = "1:7b8963a5f5bb45d0b3c18806459c02b2284a4267c8c7e9444606e95b95b51fe3"
name = "k8s.io/api" name = "k8s.io/api"
packages = [ packages = [
"admission/v1beta1", "admission/v1beta1",
@ -1210,7 +1308,7 @@
[[projects]] [[projects]]
branch = "release-1.14" branch = "release-1.14"
digest = "1:c96059b6dbbebcfb60546204e7b4db08c6c663770211f2f6859d04fc8cf381a1" digest = "1:c10a6fffe98df81cdaaeef73a38e4d669d59d2b46a3fe18565d5eb7264d19255"
name = "k8s.io/apimachinery" name = "k8s.io/apimachinery"
packages = [ packages = [
"pkg/api/equality", "pkg/api/equality",
@ -1272,7 +1370,7 @@
[[projects]] [[projects]]
branch = "release-1.14" branch = "release-1.14"
digest = "1:ecb8670ee370bbd8174cc4012f6480171e4738ffa532fa340127ab89328a8094" digest = "1:71c95d81a294dcee66147ff711896968d512b05df9bf6183cb289c6570c60b4f"
name = "k8s.io/apiserver" name = "k8s.io/apiserver"
packages = [ packages = [
"pkg/authentication/authenticator", "pkg/authentication/authenticator",
@ -1286,7 +1384,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:5439c463e465209609af21f7e384fd51cb5a7c839c35619f6acb000343ccc04f" digest = "1:1617a9d82f05ddcd88c9f3638359de6c12012f61f0fea110a37f5fc1861dc48b"
name = "k8s.io/cli-runtime" name = "k8s.io/cli-runtime"
packages = [ packages = [
"pkg/genericclioptions", "pkg/genericclioptions",
@ -1306,7 +1404,7 @@
revision = "44a48934c135b31e4f1c0d12e91d384e1cb2304c" revision = "44a48934c135b31e4f1c0d12e91d384e1cb2304c"
[[projects]] [[projects]]
digest = "1:f90ed84da7b41cd354ad9e8980a0d44b0371ff716c25efb157b6008454a23324" digest = "1:8774c035808c344c148ba5135b282d487561233ee3be10f6115ea9a9da5e1c56"
name = "k8s.io/client-go" name = "k8s.io/client-go"
packages = [ packages = [
"discovery", "discovery",
@ -1459,7 +1557,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:5f615d024e16938abfe73784c156d5da647ef74e8d16ebb1cf2e2087f7b6ddcf" digest = "1:d8f05387026197d55244f5866ea172e360c3f1602bea51ba90c72a7a43ecdce6"
name = "k8s.io/kube-openapi" name = "k8s.io/kube-openapi"
packages = [ packages = [
"pkg/common", "pkg/common",
@ -1472,7 +1570,7 @@
[[projects]] [[projects]]
branch = "release-1.14" branch = "release-1.14"
digest = "1:0c96fb4f93ffc4e978e32e5194b98a7078b3387db2991eeaaad8db202c006f46" digest = "1:3e8a09f07ca1d0163720064d0bcb567fdc85338e02bd63c6d84786be8b24ebdb"
name = "k8s.io/kubernetes" name = "k8s.io/kubernetes"
packages = [ packages = [
"pkg/api/legacyscheme", "pkg/api/legacyscheme",
@ -1597,7 +1695,7 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:12092f1fa23f0a229362b8ab287e9acf865599986bfdbd34c2f63912462ee756" digest = "1:97af0e3995afafd52fc0135efaa3290f1f3326fd184e0ef48060f76fab51c6ef"
name = "k8s.io/utils" name = "k8s.io/utils"
packages = [ packages = [
"buffer", "buffer",
@ -1621,7 +1719,7 @@
source = "https://github.com/dmcgowan/letsencrypt.git" source = "https://github.com/dmcgowan/letsencrypt.git"
[[projects]] [[projects]]
digest = "1:64e0041f63a38381fcc692dc48af9e7cd38844423f2a8ca86c609f1806547c92" digest = "1:cb422c75bab66a8339a38b64e837f3b28f3d5a8c06abd7b9048f420363baa18a"
name = "sigs.k8s.io/kustomize" name = "sigs.k8s.io/kustomize"
packages = [ packages = [
"pkg/commands/build", "pkg/commands/build",
@ -1678,12 +1776,15 @@
"github.com/asaskevich/govalidator", "github.com/asaskevich/govalidator",
"github.com/containerd/containerd/reference", "github.com/containerd/containerd/reference",
"github.com/containerd/containerd/remotes", "github.com/containerd/containerd/remotes",
"github.com/containerd/containerd/remotes/docker", "github.com/deislabs/oras/pkg/auth",
"github.com/deislabs/oras/pkg/auth/docker",
"github.com/deislabs/oras/pkg/content", "github.com/deislabs/oras/pkg/content",
"github.com/deislabs/oras/pkg/oras", "github.com/deislabs/oras/pkg/oras",
"github.com/docker/distribution/configuration", "github.com/docker/distribution/configuration",
"github.com/docker/distribution/registry", "github.com/docker/distribution/registry",
"github.com/docker/distribution/registry/auth/htpasswd",
"github.com/docker/distribution/registry/storage/driver/inmemory", "github.com/docker/distribution/registry/storage/driver/inmemory",
"github.com/docker/docker/pkg/term",
"github.com/docker/go-units", "github.com/docker/go-units",
"github.com/evanphx/json-patch", "github.com/evanphx/json-patch",
"github.com/ghodss/yaml", "github.com/ghodss/yaml",
@ -1701,6 +1802,7 @@
"github.com/stretchr/testify/assert", "github.com/stretchr/testify/assert",
"github.com/stretchr/testify/suite", "github.com/stretchr/testify/suite",
"github.com/xeipuuv/gojsonschema", "github.com/xeipuuv/gojsonschema",
"golang.org/x/crypto/bcrypt",
"golang.org/x/crypto/openpgp", "golang.org/x/crypto/openpgp",
"golang.org/x/crypto/openpgp/clearsign", "golang.org/x/crypto/openpgp/clearsign",
"golang.org/x/crypto/openpgp/errors", "golang.org/x/crypto/openpgp/errors",

@ -44,7 +44,7 @@
[[constraint]] [[constraint]]
name = "github.com/deislabs/oras" name = "github.com/deislabs/oras"
version = "~0.3.3" version = "0.4.0"
[[constraint]] [[constraint]]
name = "github.com/docker/go-units" name = "github.com/docker/go-units"
@ -76,11 +76,6 @@
branch = "master" branch = "master"
source = "https://github.com/dmcgowan/letsencrypt.git" source = "https://github.com/dmcgowan/letsencrypt.git"
# https://github.com/bugsnag/bugsnag-go/issues/96
[[override]]
name = "github.com/bugsnag/bugsnag-go"
version = "=1.3.2"
# gopkg.in is broken # gopkg.in is broken
# #
# https://github.com/golang/dep/issues/1760 # https://github.com/golang/dep/issues/1760

@ -18,14 +18,13 @@ package main
import ( import (
"io" "io"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/pkg/action" "helm.sh/helm/pkg/action"
) )
const chartHelp = ` const chartHelp = `
This command consists of multiple subcommands to interact with charts and registries. This command consists of multiple subcommands to work with the chart cache.
It can be used to push, pull, tag, list, or remove Helm charts. It can be used to push, pull, tag, list, or remove Helm charts.
Example usage: Example usage:
@ -48,8 +47,3 @@ func newChartCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
) )
return cmd return cmd
} }
// TODO remove once WARN lines removed from oras or containerd
func init() {
logrus.SetLevel(logrus.ErrorLevel)
}

@ -35,11 +35,11 @@ configures the maximum length of the revision list returned.
The historical release set is printed as a formatted table, e.g: The historical release set is printed as a formatted table, e.g:
$ helm history angry-bird --max=4 $ helm history angry-bird --max=4
REVISION UPDATED STATUS CHART DESCRIPTION REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 Initial install 1 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 1.0 Initial install
2 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 Upgraded successfully 2 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 1.0 Upgraded successfully
3 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 Rolled back to 2 3 Mon Oct 3 10:15:13 2016 superseded alpine-0.1.0 1.0 Rolled back to 2
4 Mon Oct 3 10:15:13 2016 deployed alpine-0.1.0 Upgraded successfully 4 Mon Oct 3 10:15:13 2016 deployed alpine-0.1.0 1.0 Upgraded successfully
` `
func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {

@ -0,0 +1,45 @@
/*
Copyright The Helm Authors.
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 (
"io"
"github.com/spf13/cobra"
"helm.sh/helm/pkg/action"
)
const registryHelp = `
This command consists of multiple subcommands to interact with registries.
It can be used to login to or logout from a registry.
Example usage:
$ helm registry login [URL]
`
func newRegistryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "registry",
Short: "login to or logout from a registry",
Long: registryHelp,
}
cmd.AddCommand(
newRegistryLoginCmd(cfg, out),
newRegistryLogoutCmd(cfg, out),
)
return cmd
}

@ -0,0 +1,134 @@
/*
Copyright The Helm Authors.
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 (
"bufio"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"github.com/docker/docker/pkg/term"
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/action"
)
const registryLoginDesc = `
Authenticate to a remote registry.
`
func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
var usernameOpt, passwordOpt string
var passwordFromStdinOpt bool
cmd := &cobra.Command{
Use: "login [host]",
Short: "login to a registry",
Long: registryLoginDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
hostname := args[0]
username, password, err := getUsernamePassword(usernameOpt, passwordOpt, passwordFromStdinOpt)
if err != nil {
return err
}
return action.NewRegistryLogin(cfg).Run(out, hostname, username, password)
},
}
f := cmd.Flags()
f.StringVarP(&usernameOpt, "username", "u", "", "registry username")
f.StringVarP(&passwordOpt, "password", "p", "", "registry password or identity token")
f.BoolVarP(&passwordFromStdinOpt, "password-stdin", "", false, "read password or identity token from stdin")
return cmd
}
// Adapted from https://github.com/deislabs/oras
func getUsernamePassword(usernameOpt string, passwordOpt string, passwordFromStdinOpt bool) (string, string, error) {
var err error
username := usernameOpt
password := passwordOpt
if passwordFromStdinOpt {
passwordFromStdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return "", "", err
}
password = strings.TrimSuffix(string(passwordFromStdin), "\n")
password = strings.TrimSuffix(password, "\r")
} else if password == "" {
if username == "" {
username, err = readLine("Username: ", false)
if err != nil {
return "", "", err
}
username = strings.TrimSpace(username)
}
if username == "" {
password, err = readLine("Token: ", true)
if err != nil {
return "", "", err
} else if password == "" {
return "", "", errors.New("token required")
}
} else {
password, err = readLine("Password: ", true)
if err != nil {
return "", "", err
} else if password == "" {
return "", "", errors.New("password required")
}
}
} else {
fmt.Fprintln(os.Stderr, "WARNING! Using --password via the CLI is insecure. Use --password-stdin.")
}
return username, password, nil
}
// Copied/adapted from https://github.com/deislabs/oras
func readLine(prompt string, silent bool) (string, error) {
fmt.Print(prompt)
if silent {
fd := os.Stdin.Fd()
state, err := term.SaveState(fd)
if err != nil {
return "", err
}
term.DisableEcho(fd, state)
defer term.RestoreTerminal(fd, state)
}
reader := bufio.NewReader(os.Stdin)
line, _, err := reader.ReadLine()
if err != nil {
return "", err
}
if silent {
fmt.Println()
}
return string(line), nil
}

@ -0,0 +1,43 @@
/*
Copyright The Helm Authors.
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 (
"io"
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/action"
)
const registryLogoutDesc = `
Remove credentials stored for a remote registry.
`
func newRegistryLogoutCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
return &cobra.Command{
Use: "logout [host]",
Short: "logout from a registry",
Long: registryLogoutDesc,
Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
hostname := args[0]
return action.NewRegistryLogout(cfg).Run(out, hostname)
},
}
}

@ -17,9 +17,11 @@ limitations under the License.
package main // import "helm.sh/helm/cmd/helm" package main // import "helm.sh/helm/cmd/helm"
import ( import (
"context"
"io" "io"
"path/filepath"
"github.com/containerd/containerd/remotes/docker" auth "github.com/deislabs/oras/pkg/auth/docker"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require" "helm.sh/helm/cmd/helm/require"
@ -68,10 +70,23 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
// Add the registry client based on settings // Add the registry client based on settings
// TODO: Move this elsewhere (first, settings.Init() must move) // TODO: Move this elsewhere (first, settings.Init() must move)
// TODO: handle errors, dont panic
credentialsFile := filepath.Join(settings.Home.Registry(), registry.CredentialsFileBasename)
client, err := auth.NewClient(credentialsFile)
if err != nil {
panic(err)
}
resolver, err := client.Resolver(context.Background())
if err != nil {
panic(err)
}
actionConfig.RegistryClient = registry.NewClient(&registry.ClientOptions{ actionConfig.RegistryClient = registry.NewClient(&registry.ClientOptions{
Out: out, Out: out,
Authorizer: registry.Authorizer{
Client: client,
},
Resolver: registry.Resolver{ Resolver: registry.Resolver{
Resolver: docker.NewResolver(docker.ResolverOptions{}), Resolver: resolver,
}, },
CacheRootDir: settings.Home.Registry(), CacheRootDir: settings.Home.Registry(),
}) })
@ -87,6 +102,9 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
newRepoCmd(out), newRepoCmd(out),
newSearchCmd(out), newSearchCmd(out),
newVerifyCmd(out), newVerifyCmd(out),
// registry/chart cache commands
newRegistryCmd(actionConfig, out),
newChartCmd(actionConfig, out), newChartCmd(actionConfig, out),
// release commands // release commands

@ -1,3 +1,3 @@
REVISION UPDATED STATUS CHART DESCRIPTION REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 Release mock 3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 Release mock 4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 1.0 Release mock

@ -1 +1 @@
[{"revision":3,"updated":"1977-09-02 22:04:05 +0000 UTC","status":"superseded","chart":"foo-0.1.0-beta.1","description":"Release mock"},{"revision":4,"updated":"1977-09-02 22:04:05 +0000 UTC","status":"deployed","chart":"foo-0.1.0-beta.1","description":"Release mock"}] [{"revision":3,"updated":"1977-09-02 22:04:05 +0000 UTC","status":"superseded","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"},{"revision":4,"updated":"1977-09-02 22:04:05 +0000 UTC","status":"deployed","chart":"foo-0.1.0-beta.1","app_version":"1.0","description":"Release mock"}]

@ -1,5 +1,5 @@
REVISION UPDATED STATUS CHART DESCRIPTION REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 Release mock 1 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
2 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 Release mock 2 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 Release mock 3 1977-09-02 22:04:05 +0000 UTC superseded foo-0.1.0-beta.1 1.0 Release mock
4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 Release mock 4 1977-09-02 22:04:05 +0000 UTC deployed foo-0.1.0-beta.1 1.0 Release mock

@ -1,9 +1,11 @@
- chart: foo-0.1.0-beta.1 - app_version: "1.0"
chart: foo-0.1.0-beta.1
description: Release mock description: Release mock
revision: 3 revision: 3
status: superseded status: superseded
updated: 1977-09-02 22:04:05 +0000 UTC updated: 1977-09-02 22:04:05 +0000 UTC
- chart: foo-0.1.0-beta.1 - app_version: "1.0"
chart: foo-0.1.0-beta.1
description: Release mock description: Release mock
revision: 4 revision: 4
status: deployed status: deployed

@ -27,8 +27,10 @@ import (
) )
const uninstallDesc = ` const uninstallDesc = `
This command takes a release name, and then uninstalls the release from Kubernetes. This command takes a release name and uninstalls the release.
It removes all of the resources associated with the last release of the chart.
It removes all of the resources associated with the last release of the chart
as well as the release history, freeing it up for future use.
Use the '--dry-run' flag to see which releases will be uninstalled without actually Use the '--dry-run' flag to see which releases will be uninstalled without actually
uninstalling them. uninstalling them.
@ -41,7 +43,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
Use: "uninstall RELEASE_NAME [...]", Use: "uninstall RELEASE_NAME [...]",
Aliases: []string{"del", "delete", "un"}, Aliases: []string{"del", "delete", "un"},
SuggestFor: []string{"remove", "rm"}, SuggestFor: []string{"remove", "rm"},
Short: "given a release name, uninstall the release from Kubernetes", Short: "uninstall a release",
Long: uninstallDesc, Long: uninstallDesc,
Args: require.MinimumNArgs(1), Args: require.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@ -64,7 +66,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f := cmd.Flags() f := cmd.Flags()
f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall") f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall")
f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation")
f.BoolVar(&client.Purge, "purge", false, "remove the release from the store and make its name free for later use") f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history")
f.Int64Var(&client.Timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)") f.Int64Var(&client.Timeout, "timeout", 300, "time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks)")
return cmd return cmd

@ -52,9 +52,9 @@ func TestUninstall(t *testing.T) {
rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "aeneas"})}, rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "aeneas"})},
}, },
{ {
name: "purge", name: "keep history",
cmd: "uninstall aeneas --purge", cmd: "uninstall aeneas --keep-history",
golden: "output/uninstall-purge.txt", golden: "output/uninstall-keep-history.txt",
rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "aeneas"})}, rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "aeneas"})},
}, },
{ {

@ -15,6 +15,16 @@ Here's an exhaustive list of all the major changes introduced in Helm 3.
In Helm 3, Helm switched the Go import path over from `k8s.io/helm` to `helm.sh/helm`. If you intend In Helm 3, Helm switched the Go import path over from `k8s.io/helm` to `helm.sh/helm`. If you intend
to upgrade to the Helm 3 Go client libraries, make sure to change your import paths. to upgrade to the Helm 3 Go client libraries, make sure to change your import paths.
### Helm delete
In order to better align the verbiage from other package managers, `helm delete` was re-named to
`helm uninstall`. `helm delete` is still retained as an alias to `helm uninstall`, so either form
can be used.
In Helm 2, in order to purge the release ledger, the `--purge` flag had to be provided. This
functionality is now enabled by default. To retain the previous behaviour, use
`helm uninstall --keep-history`.
## Installing ## Installing

@ -82,18 +82,16 @@ You must have a working Go environment with
```console ```console
$ cd $GOPATH $ cd $GOPATH
$ mkdir -p src/k8s.io $ mkdir -p src/helm.sh
$ cd src/k8s.io $ cd src/helm.sh
$ git clone https://github.com/helm/helm.git $ git clone https://github.com/helm/helm.git
$ cd helm $ cd helm
$ make bootstrap build $ make
``` ```
The `bootstrap` target will attempt to install dependencies, rebuild the If required, it will first install dependencies, rebuild the
`vendor/` tree, and validate configuration. `vendor/` tree, and validate configuration. It will then compile `helm` and
place it in `bin/helm`.
The `build` target will compile `helm` and place it in `bin/helm`.
## Conclusion ## Conclusion

@ -34,6 +34,7 @@ type releaseInfo struct {
Updated string `json:"updated"` Updated string `json:"updated"`
Status string `json:"status"` Status string `json:"status"`
Chart string `json:"chart"` Chart string `json:"chart"`
AppVersion string `json:"app_version"`
Description string `json:"description"` Description string `json:"description"`
} }
@ -142,11 +143,13 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
s := r.Info.Status.String() s := r.Info.Status.String()
v := r.Version v := r.Version
d := r.Info.Description d := r.Info.Description
a := formatAppVersion(r.Chart)
rInfo := releaseInfo{ rInfo := releaseInfo{
Revision: v, Revision: v,
Status: s, Status: s,
Chart: c, Chart: c,
AppVersion: a,
Description: d, Description: d,
} }
if !r.Info.LastDeployed.IsZero() { if !r.Info.LastDeployed.IsZero() {
@ -162,10 +165,10 @@ func getReleaseHistory(rls []*release.Release) (history releaseHistory) {
func formatAsTable(releases releaseHistory) []byte { func formatAsTable(releases releaseHistory) []byte {
tbl := uitable.New() tbl := uitable.New()
tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "DESCRIPTION") tbl.AddRow("REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "DESCRIPTION")
for i := 0; i <= len(releases)-1; i++ { for i := 0; i <= len(releases)-1; i++ {
r := releases[i] r := releases[i]
tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.Description) tbl.AddRow(r.Revision, r.Updated, r.Status, r.Chart, r.AppVersion, r.Description)
} }
return tbl.Bytes() return tbl.Bytes()
} }
@ -178,3 +181,12 @@ func formatChartname(c *chart.Chart) string {
} }
return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version) return fmt.Sprintf("%s-%s", c.Name(), c.Metadata.Version)
} }
func formatAppVersion(c *chart.Chart) string {
if c == nil || c.Metadata == nil {
// This is an edge case that has happened in prod, though we don't
// know how: https://github.com/helm/helm/issues/1347
return "MISSING"
}
return c.AppVersion()
}

@ -0,0 +1,38 @@
/*
Copyright The Helm Authors.
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 action
import (
"io"
)
// RegistryLogin performs a registry login operation.
type RegistryLogin struct {
cfg *Configuration
}
// NewRegistryLogin creates a new RegistryLogin object with the given configuration.
func NewRegistryLogin(cfg *Configuration) *RegistryLogin {
return &RegistryLogin{
cfg: cfg,
}
}
// Run executes the registry login operation
func (a *RegistryLogin) Run(out io.Writer, hostname string, username string, password string) error {
return a.cfg.RegistryClient.Login(hostname, username, password)
}

@ -0,0 +1,38 @@
/*
Copyright The Helm Authors.
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 action
import (
"io"
)
// RegistryLogout performs a registry login operation.
type RegistryLogout struct {
cfg *Configuration
}
// NewRegistryLogout creates a new RegistryLogout object with the given configuration.
func NewRegistryLogout(cfg *Configuration) *RegistryLogout {
return &RegistryLogout{
cfg: cfg,
}
}
// Run executes the registry logout operation
func (a *RegistryLogout) Run(out io.Writer, hostname string) error {
return a.cfg.RegistryClient.Logout(hostname)
}

@ -38,7 +38,7 @@ type Uninstall struct {
DisableHooks bool DisableHooks bool
DryRun bool DryRun bool
Purge bool KeepHistory bool
Timeout int64 Timeout int64
} }
@ -78,7 +78,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
// TODO: Are there any cases where we want to force a delete even if it's // TODO: Are there any cases where we want to force a delete even if it's
// already marked deleted? // already marked deleted?
if rel.Info.Status == release.StatusUninstalled { if rel.Info.Status == release.StatusUninstalled {
if u.Purge { if !u.KeepHistory {
if err := u.purgeReleases(rels...); err != nil { if err := u.purgeReleases(rels...); err != nil {
return nil, errors.Wrap(err, "uninstall: Failed to purge the release") return nil, errors.Wrap(err, "uninstall: Failed to purge the release")
} }
@ -119,7 +119,7 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error)
rel.Info.Status = release.StatusUninstalled rel.Info.Status = release.StatusUninstalled
rel.Info.Description = "Uninstallation complete" rel.Info.Description = "Uninstallation complete"
if u.Purge { if !u.KeepHistory {
u.cfg.Log("purge requested for %s", name) u.cfg.Log("purge requested for %s", name)
err := u.purgeReleases(rels...) err := u.purgeReleases(rels...)
return res, errors.Wrap(err, "uninstall: Failed to purge the release") return res, errors.Wrap(err, "uninstall: Failed to purge the release")

@ -102,3 +102,11 @@ func (ch *Chart) ChartFullPath() string {
func (ch *Chart) Validate() error { func (ch *Chart) Validate() error {
return ch.Metadata.Validate() return ch.Metadata.Validate()
} }
// AppVersion returns the appversion of the chart.
func (ch *Chart) AppVersion() string {
if ch.Metadata == nil {
return ""
}
return ch.Metadata.AppVersion
}

@ -73,7 +73,7 @@ version: 0.1.0
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. # incremented each time you make changes to the application.
appVersion: 0.1.0 appVersion: 1.16.0
` `
const defaultValues = `# Default values for %s. const defaultValues = `# Default values for %s.
@ -211,7 +211,7 @@ spec:
spec: spec:
containers: containers:
- name: {{ .Chart.Name }} - name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Release.AppVersion }}" image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }} imagePullPolicy: {{ .Values.image.pullPolicy }}
ports: ports:
- name: http - name: http

@ -25,7 +25,7 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/Masterminds/sprig" "github.com/Masterminds/sprig"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
// funcMap returns a mapping of all of the functions that Engine has. // funcMap returns a mapping of all of the functions that Engine has.

@ -0,0 +1,28 @@
/*
Copyright The Helm Authors.
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 registry // import "helm.sh/helm/pkg/registry"
import (
"github.com/deislabs/oras/pkg/auth"
)
type (
// Authorizer handles registry auth operations
Authorizer struct {
auth.Client
}
)

@ -29,7 +29,7 @@ import (
"time" "time"
orascontent "github.com/deislabs/oras/pkg/content" orascontent "github.com/deislabs/oras/pkg/content"
"github.com/docker/go-units" units "github.com/docker/go-units"
checksum "github.com/opencontainers/go-digest" checksum "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"

@ -28,27 +28,34 @@ import (
"helm.sh/helm/pkg/chart" "helm.sh/helm/pkg/chart"
) )
const (
CredentialsFileBasename = "config.json"
)
type ( type (
// ClientOptions is used to construct a new client // ClientOptions is used to construct a new client
ClientOptions struct { ClientOptions struct {
Out io.Writer Out io.Writer
Authorizer Authorizer
Resolver Resolver Resolver Resolver
CacheRootDir string CacheRootDir string
} }
// Client works with OCI-compliant registries and local Helm chart cache // Client works with OCI-compliant registries and local Helm chart cache
Client struct { Client struct {
out io.Writer out io.Writer
resolver Resolver authorizer Authorizer
cache *filesystemCache // TODO: something more robust resolver Resolver
cache *filesystemCache // TODO: something more robust
} }
) )
// NewClient returns a new registry client with config // NewClient returns a new registry client with config
func NewClient(options *ClientOptions) *Client { func NewClient(options *ClientOptions) *Client {
return &Client{ return &Client{
out: options.Out, out: options.Out,
resolver: options.Resolver, resolver: options.Resolver,
authorizer: options.Authorizer,
cache: &filesystemCache{ cache: &filesystemCache{
out: options.Out, out: options.Out,
rootDir: options.CacheRootDir, rootDir: options.CacheRootDir,
@ -57,6 +64,26 @@ func NewClient(options *ClientOptions) *Client {
} }
} }
// Login logs into a registry
func (c *Client) Login(hostname string, username string, password string) error {
err := c.authorizer.Login(context.Background(), hostname, username, password)
if err != nil {
return err
}
fmt.Fprint(c.out, "Login succeeded\n")
return nil
}
// Logout logs out of a registry
func (c *Client) Logout(hostname string) error {
err := c.authorizer.Logout(context.Background(), hostname)
if err != nil {
return err
}
fmt.Fprint(c.out, "Logout succeeded\n")
return nil
}
// PushChart uploads a chart to a registry // PushChart uploads a chart to a registry
func (c *Client) PushChart(ref *Reference) error { func (c *Client) PushChart(ref *Reference) error {
c.setDefaultTag(ref) c.setDefaultTag(ref)
@ -65,7 +92,7 @@ func (c *Client) PushChart(ref *Reference) error {
if err != nil { if err != nil {
return err return err
} }
err = oras.Push(context.Background(), c.resolver, ref.String(), c.cache.store, layers) _, err = oras.Push(context.Background(), c.resolver, ref.String(), c.cache.store, layers)
if err != nil { if err != nil {
return err return err
} }
@ -82,7 +109,7 @@ func (c *Client) PushChart(ref *Reference) error {
func (c *Client) PullChart(ref *Reference) error { func (c *Client) PullChart(ref *Reference) error {
c.setDefaultTag(ref) c.setDefaultTag(ref)
fmt.Fprintf(c.out, "%s: Pulling from %s\n", ref.Tag, ref.Repo) fmt.Fprintf(c.out, "%s: Pulling from %s\n", ref.Tag, ref.Repo)
layers, err := oras.Pull(context.Background(), c.resolver, ref.String(), c.cache.store, KnownMediaTypes()...) _, layers, err := oras.Pull(context.Background(), c.resolver, ref.String(), c.cache.store, oras.WithAllowedMediaTypes(KnownMediaTypes()))
if err != nil { if err != nil {
return err return err
} }

@ -21,22 +21,29 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net" "net"
"os" "os"
"path/filepath"
"testing" "testing"
"time" "time"
"github.com/containerd/containerd/remotes/docker" auth "github.com/deislabs/oras/pkg/auth/docker"
"github.com/docker/distribution/configuration" "github.com/docker/distribution/configuration"
"github.com/docker/distribution/registry" "github.com/docker/distribution/registry"
_ "github.com/docker/distribution/registry/auth/htpasswd"
_ "github.com/docker/distribution/registry/storage/driver/inmemory" _ "github.com/docker/distribution/registry/storage/driver/inmemory"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"golang.org/x/crypto/bcrypt"
"helm.sh/helm/pkg/chart" "helm.sh/helm/pkg/chart"
) )
var ( var (
testCacheRootDir = "helm-registry-test" testCacheRootDir = "helm-registry-test"
testHtpasswdFileBasename = "authtest.htpasswd"
testUsername = "myuser"
testPassword = "mypass"
) )
type RegistryClientTestSuite struct { type RegistryClientTestSuite struct {
@ -49,28 +56,52 @@ type RegistryClientTestSuite struct {
func (suite *RegistryClientTestSuite) SetupSuite() { func (suite *RegistryClientTestSuite) SetupSuite() {
suite.CacheRootDir = testCacheRootDir suite.CacheRootDir = testCacheRootDir
os.RemoveAll(suite.CacheRootDir)
os.Mkdir(suite.CacheRootDir, 0700)
// Init test client
var out bytes.Buffer var out bytes.Buffer
suite.Out = &out suite.Out = &out
credentialsFile := filepath.Join(suite.CacheRootDir, CredentialsFileBasename)
client, err := auth.NewClient(credentialsFile)
suite.Nil(err, "no error creating auth client")
resolver, err := client.Resolver(context.Background())
suite.Nil(err, "no error creating resolver")
// Init test client
suite.RegistryClient = NewClient(&ClientOptions{ suite.RegistryClient = NewClient(&ClientOptions{
Out: suite.Out, Out: suite.Out,
Authorizer: Authorizer{
Client: client,
},
Resolver: Resolver{ Resolver: Resolver{
Resolver: docker.NewResolver(docker.ResolverOptions{}), Resolver: resolver,
}, },
CacheRootDir: suite.CacheRootDir, CacheRootDir: suite.CacheRootDir,
}) })
// create htpasswd file (w BCrypt, which is required)
pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
suite.Nil(err, "no error generating bcrypt password for test htpasswd file")
htpasswdPath := filepath.Join(suite.CacheRootDir, testHtpasswdFileBasename)
err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testUsername, string(pwBytes))), 0644)
suite.Nil(err, "no error creating test htpasswd file")
// Registry config // Registry config
config := &configuration.Configuration{} config := &configuration.Configuration{}
port, err := getFreePort() port, err := getFreePort()
if err != nil { suite.Nil(err, "no error finding free port for test registry")
suite.Nil(err, "no error finding free port for test registry")
}
suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port) suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
config.HTTP.Addr = fmt.Sprintf(":%d", port) config.HTTP.Addr = fmt.Sprintf(":%d", port)
config.HTTP.DrainTimeout = time.Duration(10) * time.Second config.HTTP.DrainTimeout = time.Duration(10) * time.Second
config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
config.Auth = configuration.Auth{
"htpasswd": configuration.Parameters{
"realm": "localhost",
"path": htpasswdPath,
},
}
dockerRegistry, err := registry.NewRegistry(context.Background(), config) dockerRegistry, err := registry.NewRegistry(context.Background(), config)
suite.Nil(err, "no error creating test registry") suite.Nil(err, "no error creating test registry")
@ -82,7 +113,15 @@ func (suite *RegistryClientTestSuite) TearDownSuite() {
os.RemoveAll(suite.CacheRootDir) os.RemoveAll(suite.CacheRootDir)
} }
func (suite *RegistryClientTestSuite) Test_0_SaveChart() { func (suite *RegistryClientTestSuite) Test_0_Login() {
err := suite.RegistryClient.Login(suite.DockerRegistryHost, "badverybad", "ohsobad")
suite.NotNil(err, "error logging into registry with bad credentials")
err = suite.RegistryClient.Login(suite.DockerRegistryHost, testUsername, testPassword)
suite.Nil(err, "no error logging into registry with good credentials")
}
func (suite *RegistryClientTestSuite) Test_1_SaveChart() {
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
suite.Nil(err) suite.Nil(err)
@ -101,7 +140,7 @@ func (suite *RegistryClientTestSuite) Test_0_SaveChart() {
suite.Nil(err) suite.Nil(err)
} }
func (suite *RegistryClientTestSuite) Test_1_LoadChart() { func (suite *RegistryClientTestSuite) Test_2_LoadChart() {
// non-existent ref // non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
@ -118,7 +157,7 @@ func (suite *RegistryClientTestSuite) Test_1_LoadChart() {
suite.Equal("1.2.3", ch.Metadata.Version) suite.Equal("1.2.3", ch.Metadata.Version)
} }
func (suite *RegistryClientTestSuite) Test_2_PushChart() { func (suite *RegistryClientTestSuite) Test_3_PushChart() {
// non-existent ref // non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
@ -133,7 +172,7 @@ func (suite *RegistryClientTestSuite) Test_2_PushChart() {
suite.Nil(err) suite.Nil(err)
} }
func (suite *RegistryClientTestSuite) Test_3_PullChart() { func (suite *RegistryClientTestSuite) Test_4_PullChart() {
// non-existent ref // non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
@ -148,12 +187,12 @@ func (suite *RegistryClientTestSuite) Test_3_PullChart() {
suite.Nil(err) suite.Nil(err)
} }
func (suite *RegistryClientTestSuite) Test_4_PrintChartTable() { func (suite *RegistryClientTestSuite) Test_5_PrintChartTable() {
err := suite.RegistryClient.PrintChartTable() err := suite.RegistryClient.PrintChartTable()
suite.Nil(err) suite.Nil(err)
} }
func (suite *RegistryClientTestSuite) Test_5_RemoveChart() { func (suite *RegistryClientTestSuite) Test_6_RemoveChart() {
// non-existent ref // non-existent ref
ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
@ -168,6 +207,14 @@ func (suite *RegistryClientTestSuite) Test_5_RemoveChart() {
suite.Nil(err) suite.Nil(err)
} }
func (suite *RegistryClientTestSuite) Test_7_Logout() {
err := suite.RegistryClient.Logout("this-host-aint-real:5000")
suite.NotNil(err, "error logging out of registry that has no entry")
err = suite.RegistryClient.Logout(suite.DockerRegistryHost)
suite.Nil(err, "no error logging out of registry")
}
func TestRegistryClientTestSuite(t *testing.T) { func TestRegistryClientTestSuite(t *testing.T) {
suite.Run(t, new(RegistryClientTestSuite)) suite.Run(t, new(RegistryClientTestSuite))
} }

@ -71,8 +71,9 @@ func Mock(opts *MockReleaseOptions) *Release {
if opts.Chart == nil { if opts.Chart == nil {
ch = &chart.Chart{ ch = &chart.Chart{
Metadata: &chart.Metadata{ Metadata: &chart.Metadata{
Name: "foo", Name: "foo",
Version: "0.1.0-beta.1", Version: "0.1.0-beta.1",
AppVersion: "1.0",
}, },
Templates: []*chart.File{ Templates: []*chart.File{
{Name: "templates/foo.tpl", Data: []byte(MockManifest)}, {Name: "templates/foo.tpl", Data: []byte(MockManifest)},

@ -287,8 +287,8 @@ _helm_delete()
local_nonpersistent_flags+=("--dry-run") local_nonpersistent_flags+=("--dry-run")
flags+=("--no-hooks") flags+=("--no-hooks")
local_nonpersistent_flags+=("--no-hooks") local_nonpersistent_flags+=("--no-hooks")
flags+=("--purge") flags+=("--keep-history")
local_nonpersistent_flags+=("--purge") local_nonpersistent_flags+=("--keep-history")
flags+=("--timeout=") flags+=("--timeout=")
local_nonpersistent_flags+=("--timeout=") local_nonpersistent_flags+=("--timeout=")
flags+=("--tls") flags+=("--tls")

Loading…
Cancel
Save