diff --git a/go.mod b/go.mod index 1e93c66a..b3644651 100644 --- a/go.mod +++ b/go.mod @@ -16,10 +16,10 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - github.com/temporalio/ui-server/v2 v2.31.2 + github.com/temporalio/ui-server/v2 v2.32.0 go.temporal.io/api v1.38.0 go.temporal.io/sdk v1.29.1 - go.temporal.io/server v1.25.1 + go.temporal.io/server v1.25.2 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 @@ -41,11 +41,12 @@ require ( github.com/cactus/go-statsd-client/v5 v5.1.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-oidc/v3 v3.1.0 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/coreos/go-oidc/v3 v3.11.0 // indirect + github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect @@ -57,6 +58,7 @@ require ( github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect + github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.4 // indirect @@ -141,7 +143,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/validator.v2 v2.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect modernc.org/libc v1.50.9 // indirect diff --git a/go.sum b/go.sum index fd30afe5..abc6d812 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY= cloud.google.com/go v0.114.0/go.mod h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E= cloud.google.com/go/auth v0.5.0 h1:GtSZfKJkPrZi/s3AkiHnUYVI4dTP/kg8+I3unm0omag= @@ -51,8 +50,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/go-oidc/v3 v3.1.0 h1:6avEvcdvTa1qYsOZ6I5PRkSYHzpTNWgKYmaJfaYbrRw= -github.com/coreos/go-oidc/v3 v3.1.0/go.mod h1:rEJ/idjfUyfkBit1eI1fvyr+64/g9dcKpAm8MJMesvo= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ= @@ -61,8 +60,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-farm v0.0.0-20140601200337-fc41e106ee0e/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -83,6 +82,8 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu github.com/go-faker/faker/v4 v4.4.1 h1:LY1jDgjVkBZWIhATCt+gkl0x9i/7wC61gZx73GTFb+Q= github.com/go-faker/faker/v4 v4.4.1/go.mod h1:HRLrjis+tYsbFtIHufEPTAIzcZiRu0rS9EYl2Ccwme4= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -126,6 +127,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81 h1:5lyLWsV+qCkoYqsKUDuycESh9DEIPVKN6iCFeL7ag50= +github.com/gomarkdown/markdown v0.0.0-20241105142532-d03b89096d81/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -300,8 +303,8 @@ github.com/temporalio/sqlparser v0.0.0-20231115171017-f4060bcfa6cb/go.mod h1:143 github.com/temporalio/tchannel-go v1.22.1-0.20220818200552-1be8d8cffa5b/go.mod h1:c+V9Z/ZgkzAdyGvHrvC5AsXgN+M9Qwey04cBdKYzV7U= github.com/temporalio/tchannel-go v1.22.1-0.20240528171429-1db37fdea938 h1:sEJGhmDo+0FaPWM6f0v8Tjia0H5pR6/Baj6+kS78B+M= github.com/temporalio/tchannel-go v1.22.1-0.20240528171429-1db37fdea938/go.mod h1:ezRQRwu9KQXy8Wuuv1aaFFxoCNz5CeNbVOOkh3xctbY= -github.com/temporalio/ui-server/v2 v2.31.2 h1:36PQMk7OdmPcNphyMZixvOB0n87L8mvaRgCxXO0HoDg= -github.com/temporalio/ui-server/v2 v2.31.2/go.mod h1:cl/5FOXh4Hp5SdqrgOGtl2UfNwROUryaUV8q/WJYA4I= +github.com/temporalio/ui-server/v2 v2.32.0 h1:mR6eet9n4eRkGgHcZqaJdXWK5sfQguN4LoWxQXsqpY0= +github.com/temporalio/ui-server/v2 v2.32.0/go.mod h1:b8whRt0/lbgNDzG7alSdiDzXFO8Fk783eRMhIycWtn8= github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber-common/bark v1.0.0/go.mod h1:g0ZuPcD7XiExKHynr93Q742G/sbrdVQkghrqLGOoFuY= @@ -352,8 +355,8 @@ go.temporal.io/api v1.38.0 h1:L5i+Ai7UoBa2Gq/goVHLY32064AgawxPDLkKm4I7fu4= go.temporal.io/api v1.38.0/go.mod h1:fmh06EjstyrPp6SHbjJo7yYHBfHamPE4SytM+2NRejc= go.temporal.io/sdk v1.29.1 h1:y+sUMbUhTU9rj50mwIZAPmcXCtgUdOWS9xHDYRYSgZ0= go.temporal.io/sdk v1.29.1/go.mod h1:kp//DRvn3CqQVBCtjL51Oicp9wrZYB2s6row1UgzcKQ= -go.temporal.io/server v1.25.1 h1:iDkzzDMdmOPZUctLegF5kWY/h1W/MTbMZ8hsBkHBIV4= -go.temporal.io/server v1.25.1/go.mod h1:I/6PLZkyhCC9OyNfuBCYfmSEi7DCxanzC2378Pojlf0= +go.temporal.io/server v1.25.2 h1:AVlFfNStYVvgyIG/QlfPsp1RgiP+IBuMnEX/kIYAHJ4= +go.temporal.io/server v1.25.2/go.mod h1:3BzDvfiMwi9ETiv4UoE1LWhuIctR6Ep+G1RVomH9YZE= go.temporal.io/version v0.3.0 h1:dMrei9l9NyHt8nG6EB8vAwDLLTwx2SvRyucCSumAiig= go.temporal.io/version v0.3.0/go.mod h1:UA9S8/1LaKYae6TyD9NaPMJTZb911JcbqghI2CBSP78= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -412,13 +415,11 @@ golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -430,12 +431,10 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -450,7 +449,6 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -560,9 +558,6 @@ gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKK gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/temporalcli/commands.gen.go b/temporalcli/commands.gen.go index 181cd85c..c01963a0 100644 --- a/temporalcli/commands.gen.go +++ b/temporalcli/commands.gen.go @@ -271,7 +271,7 @@ type TemporalCommand struct { Env string EnvFile string LogLevel StringEnum - LogFormat string + LogFormat StringEnum Output StringEnum TimeFormat StringEnum Color StringEnum @@ -302,7 +302,8 @@ func NewTemporalCommand(cctx *CommandContext) *TemporalCommand { s.Command.PersistentFlags().StringVar(&s.EnvFile, "env-file", "", "Path to environment settings file. Defaults to `$HOME/.config/temporalio/temporal.yaml`.") s.LogLevel = NewStringEnum([]string{"debug", "info", "warn", "error", "never"}, "info") s.Command.PersistentFlags().Var(&s.LogLevel, "log-level", "Log level. Default is \"info\" for most commands and \"warn\" for `server start-dev`. Accepted values: debug, info, warn, error, never.") - s.Command.PersistentFlags().StringVar(&s.LogFormat, "log-format", "text", "Log format. Options are: text, json.") + s.LogFormat = NewStringEnum([]string{"text", "json", "pretty"}, "text") + s.Command.PersistentFlags().Var(&s.LogFormat, "log-format", "Log format. Accepted values: text, json.") s.Output = NewStringEnum([]string{"text", "json", "jsonl", "none"}, "text") s.Command.PersistentFlags().VarP(&s.Output, "output", "o", "Non-logging data output format. Accepted values: text, json, jsonl, none.") s.TimeFormat = NewStringEnum([]string{"relative", "iso", "raw"}, "relative") @@ -422,9 +423,9 @@ func NewTemporalBatchCommand(cctx *CommandContext, parent *TemporalCommand) *Tem s.Command.Use = "batch" s.Command.Short = "Manage running batch jobs" if hasHighlighting { - s.Command.Long = "List or terminate running batch jobs.\n\nA batch job executes a command on multiple Workflow Executions at once. Create\nbatch jobs by passing \x1b[1m--query\x1b[0m to commands that support it. For example, to\ncreate a batch job to cancel a set of Workflow Executions:\n\n\x1b[1mtemporal workflow cancel \\\n --query 'ExecutionStatus = \"Running\" AND WorkflowType=\"YourWorkflow\"' \\\n --reason \"Testing\"\x1b[0m\n\nQuery Quick Reference:\n\n\x1b[1m+----------------------------------------------------------------------------+\n| Composition: |\n| - Data types: String literals with single or double quotes, |\n| Numbers (integer and floating point), Booleans |\n| - Comparison: '=', '!=', '>', '>=', '<', '<=' |\n| - Expressions/Operators: 'IN array', 'BETWEEN value AND value', |\n| 'STARTS_WITH string', 'IS NULL', 'IS NOT NULL', 'expr AND expr', |\n| 'expr OR expr', '( expr )' |\n| - Array: '( comma-separated-values )' |\n| |\n| Please note: |\n| - Wrap attributes with backticks if it contains characters not in |\n| \x1b[1m[a-zA-Z0-9]\x1b[0m. |\n| - \x1b[1mSTARTS_WITH\x1b[0m is only available for Keyword search attributes. |\n+----------------------------------------------------------------------------+\x1b[0m\n\nVisit https://docs.temporal.io/visibility to read more about Search Attributes\nand Query creation." + s.Command.Long = "List or terminate running batch jobs.\n\nA batch job executes a command on multiple Workflow Executions at once. Create\nbatch jobs by passing \x1b[1m--query\x1b[0m to commands that support it. For example, to\ncreate a batch job to cancel a set of Workflow Executions:\n\n\x1b[1mtemporal workflow cancel \\\n --query 'ExecutionStatus = \"Running\" AND WorkflowType=\"YourWorkflow\"' \\\n --reason \"Testing\"\x1b[0m\n\nQuery Quick Reference:\n\n\x1b[1m+----------------------------------------------------------------------------+\n| Composition: |\n| - Data types: String literals with single or double quotes, |\n| Numbers (integer and floating point), Booleans |\n| - Comparison: '=', '!=', '>', '>=', '<', '<=' |\n| - Expressions/Operators: 'IN array', 'BETWEEN value AND value', |\n| 'STARTS_WITH string', 'IS NULL', 'IS NOT NULL', 'expr AND expr', |\n| 'expr OR expr', '( expr )' |\n| - Array: '( comma-separated-values )' |\n| |\n| Please note: |\n| - Wrap attributes with backticks if it contains characters not in |\n| [a-zA-Z0-9]. |\n| - STARTS_WITH is only available for Keyword search attributes. |\n+----------------------------------------------------------------------------+\x1b[0m\n\nVisit https://docs.temporal.io/visibility to read more about Search Attributes\nand Query creation." } else { - s.Command.Long = "List or terminate running batch jobs.\n\nA batch job executes a command on multiple Workflow Executions at once. Create\nbatch jobs by passing `--query` to commands that support it. For example, to\ncreate a batch job to cancel a set of Workflow Executions:\n\n```\ntemporal workflow cancel \\\n --query 'ExecutionStatus = \"Running\" AND WorkflowType=\"YourWorkflow\"' \\\n --reason \"Testing\"\n```\n\nQuery Quick Reference:\n\n```\n+----------------------------------------------------------------------------+\n| Composition: |\n| - Data types: String literals with single or double quotes, |\n| Numbers (integer and floating point), Booleans |\n| - Comparison: '=', '!=', '>', '>=', '<', '<=' |\n| - Expressions/Operators: 'IN array', 'BETWEEN value AND value', |\n| 'STARTS_WITH string', 'IS NULL', 'IS NOT NULL', 'expr AND expr', |\n| 'expr OR expr', '( expr )' |\n| - Array: '( comma-separated-values )' |\n| |\n| Please note: |\n| - Wrap attributes with backticks if it contains characters not in |\n| `[a-zA-Z0-9]`. |\n| - `STARTS_WITH` is only available for Keyword search attributes. |\n+----------------------------------------------------------------------------+\n```\n\nVisit https://docs.temporal.io/visibility to read more about Search Attributes\nand Query creation." + s.Command.Long = "List or terminate running batch jobs.\n\nA batch job executes a command on multiple Workflow Executions at once. Create\nbatch jobs by passing `--query` to commands that support it. For example, to\ncreate a batch job to cancel a set of Workflow Executions:\n\n```\ntemporal workflow cancel \\\n --query 'ExecutionStatus = \"Running\" AND WorkflowType=\"YourWorkflow\"' \\\n --reason \"Testing\"\n```\n\nQuery Quick Reference:\n\n```\n+----------------------------------------------------------------------------+\n| Composition: |\n| - Data types: String literals with single or double quotes, |\n| Numbers (integer and floating point), Booleans |\n| - Comparison: '=', '!=', '>', '>=', '<', '<=' |\n| - Expressions/Operators: 'IN array', 'BETWEEN value AND value', |\n| 'STARTS_WITH string', 'IS NULL', 'IS NOT NULL', 'expr AND expr', |\n| 'expr OR expr', '( expr )' |\n| - Array: '( comma-separated-values )' |\n| |\n| Please note: |\n| - Wrap attributes with backticks if it contains characters not in |\n| [a-zA-Z0-9]. |\n| - STARTS_WITH is only available for Keyword search attributes. |\n+----------------------------------------------------------------------------+\n```\n\nVisit https://docs.temporal.io/visibility to read more about Search Attributes\nand Query creation." } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalBatchDescribeCommand(cctx, &s).Command) diff --git a/temporalcli/commands.go b/temporalcli/commands.go index 0860250e..b9ba6322 100644 --- a/temporalcli/commands.go +++ b/temporalcli/commands.go @@ -442,7 +442,7 @@ func (c *TemporalCommand) preRun(cctx *CommandContext) error { return fmt.Errorf("invalid log level %q: %w", c.LogLevel.Value, err) } var handler slog.Handler - switch c.LogFormat { + switch c.LogFormat.Value { // We have a "pretty" alias for compatibility case "", "text", "pretty": handler = slog.NewTextHandler(cctx.Options.Stderr, &slog.HandlerOptions{ @@ -458,7 +458,7 @@ func (c *TemporalCommand) preRun(cctx *CommandContext) error { case "json": handler = slog.NewJSONHandler(cctx.Options.Stderr, &slog.HandlerOptions{Level: level}) default: - return fmt.Errorf("invalid log format %q", c.LogFormat) + return fmt.Errorf("invalid log format %q", c.LogFormat.Value) } cctx.Logger = slog.New(handler) } diff --git a/temporalcli/commands.workflow_reset.go b/temporalcli/commands.workflow_reset.go index e5e802a3..a4284591 100644 --- a/temporalcli/commands.workflow_reset.go +++ b/temporalcli/commands.workflow_reset.go @@ -72,38 +72,14 @@ func (c *TemporalWorkflowResetCommand) doWorkflowReset(cctx *CommandContext, cl eventID := int64(c.EventId) if c.Type.Value != "" { resetBaseRunID, eventID, err = c.getResetEventIDByType(cctx, cl) - if err != nil { - return fmt.Errorf("getting reset event ID by type failed: %w", err) - } - } - - reapplyExcludes := make([]enums.ResetReapplyExcludeType, 0) - for _, exclude := range c.ReapplyExclude.Values { - if strings.ToLower(exclude) == "all" { - for _, excludeType := range enums.ResetReapplyExcludeType_value { - if excludeType == 0 { - continue - } - reapplyExcludes = append(reapplyExcludes, enums.ResetReapplyExcludeType(excludeType)) - } - break - } - excludeType, err := enums.ResetReapplyExcludeTypeFromString(exclude) if err != nil { return err } - reapplyExcludes = append(reapplyExcludes, excludeType) } - reapplyType := enums.RESET_REAPPLY_TYPE_ALL_ELIGIBLE - if c.ReapplyType.Value != "All" { - if len(c.ReapplyExclude.Values) > 0 { - return errors.New("--reapply-type cannot be used with --reapply-exclude. Use --reapply-exclude.") - } - reapplyType, err = enums.ResetReapplyTypeFromString(c.ReapplyType.Value) - if err != nil { - return err - } + reapplyExcludes, reapplyType, err := getResetReapplyAndExcludeTypes(c.ReapplyExclude.Values, c.ReapplyType.Value) + if err != nil { + return err } cctx.Printer.Printlnf("Resetting workflow %s to event ID %d", c.WorkflowId, eventID) @@ -138,10 +114,15 @@ func (c *TemporalWorkflowResetCommand) runBatchReset(cctx *CommandContext, cl cl VisibilityQuery: c.Query, Reason: c.Reason, } + + batchResetOptions, err := c.batchResetOptions() + if err != nil { + return err + } request.Operation = &workflowservice.StartBatchOperationRequest_ResetOperation{ ResetOperation: &batch.BatchOperationReset{ Identity: clientIdentity(), - Options: c.batchResetOptions(c.Type.Value), + Options: batchResetOptions, }, } count, err := cl.CountWorkflow(cctx, &workflowservice.CountWorkflowExecutionsRequest{Query: c.Query}) @@ -160,22 +141,33 @@ func (c *TemporalWorkflowResetCommand) runBatchReset(cctx *CommandContext, cl cl return startBatchJob(cctx, cl, &request) } -func (c *TemporalWorkflowResetCommand) batchResetOptions(resetType string) *common.ResetOptions { - switch resetType { +func (c *TemporalWorkflowResetCommand) batchResetOptions() (*common.ResetOptions, error) { + reapplyExcludes, reapplyType, err := getResetReapplyAndExcludeTypes(c.ReapplyExclude.Values, c.ReapplyType.Value) + if err != nil { + return nil, err + } + + switch c.Type.Value { case "FirstWorkflowTask": return &common.ResetOptions{ - Target: &common.ResetOptions_FirstWorkflowTask{}, - } + Target: &common.ResetOptions_FirstWorkflowTask{}, + ResetReapplyExcludeTypes: reapplyExcludes, + ResetReapplyType: reapplyType, + }, nil case "LastWorkflowTask": return &common.ResetOptions{ - Target: &common.ResetOptions_LastWorkflowTask{}, - } + Target: &common.ResetOptions_LastWorkflowTask{}, + ResetReapplyExcludeTypes: reapplyExcludes, + ResetReapplyType: reapplyType, + }, nil case "BuildId": return &common.ResetOptions{ Target: &common.ResetOptions_BuildId{ BuildId: c.BuildId, }, - } + ResetReapplyExcludeTypes: reapplyExcludes, + ResetReapplyType: reapplyType, + }, nil default: panic("unsupported operation type was filtered by cli framework") } @@ -314,3 +306,38 @@ func getLastContinueAsNewID(ctx context.Context, namespace, wid, rid string, wfs } return } + +func getResetReapplyAndExcludeTypes(resetReapplyExclude []string, resetReapplyType string) ([]enums.ResetReapplyExcludeType, enums.ResetReapplyType, error) { + var err error + + var reapplyExcludes []enums.ResetReapplyExcludeType + for _, exclude := range resetReapplyExclude { + if strings.ToLower(exclude) == "all" { + for _, excludeType := range enums.ResetReapplyExcludeType_value { + if excludeType == int32(enums.RESET_REAPPLY_EXCLUDE_TYPE_UNSPECIFIED) { + continue + } + reapplyExcludes = append(reapplyExcludes, enums.ResetReapplyExcludeType(excludeType)) + } + break + } + excludeType, err := enums.ResetReapplyExcludeTypeFromString(exclude) + if err != nil { + return nil, enums.RESET_REAPPLY_TYPE_UNSPECIFIED, err + } + reapplyExcludes = append(reapplyExcludes, excludeType) + } + + returnReapplyType := enums.RESET_REAPPLY_TYPE_ALL_ELIGIBLE + if resetReapplyType != "All" { + if len(resetReapplyExclude) > 0 { + return nil, enums.RESET_REAPPLY_TYPE_UNSPECIFIED, errors.New("--reapply-type cannot be used with --reapply-exclude. Use --reapply-exclude") + } + returnReapplyType, err = enums.ResetReapplyTypeFromString(resetReapplyType) + if err != nil { + return nil, enums.RESET_REAPPLY_TYPE_UNSPECIFIED, err + } + } + + return reapplyExcludes, returnReapplyType, nil +} diff --git a/temporalcli/commands.workflow_reset_test.go b/temporalcli/commands.workflow_reset_test.go index e8da74dd..e49a09cb 100644 --- a/temporalcli/commands.workflow_reset_test.go +++ b/temporalcli/commands.workflow_reset_test.go @@ -77,6 +77,48 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ToFirstWorkflowTask() { s.Greater(activityExecutions, 1, "Should have re-executed the workflow from the beginning") } +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ToFirstWorkflowTask() { + var wfExecutions, activityExecutions int + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + activityExecutions++ + return nil, nil + }) + s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) { + workflow.ExecuteActivity(ctx, DevActivity, 1).Get(ctx, nil) + wfExecutions++ + return nil, nil + }) + + // Start the workflow + searchAttr := "keyword-" + uuid.NewString() + run, err := s.Client.ExecuteWorkflow( + s.Context, + client.StartWorkflowOptions{ + TaskQueue: s.Worker().Options.TaskQueue, + SearchAttributes: map[string]any{"CustomKeywordField": searchAttr}, + }, + DevWorkflow, + "ignored", + ) + s.NoError(err) + var junk any + s.NoError(run.Get(s.Context, &junk)) + s.Equal(1, wfExecutions) + + s.CommandHarness.Stdin.WriteString("y\n") + res := s.Execute( + "workflow", "reset", + "--address", s.Address(), + "--query", fmt.Sprintf("CustomKeywordField = '%s'", searchAttr), + "-t", "FirstWorkflowTask", + "--reason", "test-reset-FirstWorkflowTask", + ) + require.NoError(s.T(), res.Err) + s.awaitNextWorkflow(searchAttr) + s.Equal(2, wfExecutions, "Should have re-executed the workflow from the beginning") + s.Greater(activityExecutions, 1, "Should have re-executed the workflow from the beginning") +} + func (s *SharedServerSuite) TestWorkflow_Reset_ToLastWorkflowTask() { var wfExecutions, activityExecutions int s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { @@ -119,6 +161,48 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ToLastWorkflowTask() { s.Equal(1, activityExecutions, "Should not have re-executed the activity") } +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ToLastWorkflowTask() { + var wfExecutions, activityExecutions int + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + activityExecutions++ + return nil, nil + }) + s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) { + workflow.ExecuteActivity(ctx, DevActivity, 1).Get(ctx, nil) + wfExecutions++ + return nil, nil + }) + + // Start the workflow + searchAttr := "keyword-" + uuid.NewString() + run, err := s.Client.ExecuteWorkflow( + s.Context, + client.StartWorkflowOptions{ + TaskQueue: s.Worker().Options.TaskQueue, + SearchAttributes: map[string]any{"CustomKeywordField": searchAttr}, + }, + DevWorkflow, + "ignored", + ) + s.NoError(err) + var junk any + s.NoError(run.Get(s.Context, &junk)) + s.Equal(1, wfExecutions) + + s.CommandHarness.Stdin.WriteString("y\n") + res := s.Execute( + "workflow", "reset", + "--address", s.Address(), + "--query", fmt.Sprintf("CustomKeywordField = '%s'", searchAttr), + "-t", "LastWorkflowTask", + "--reason", "test-reset-LastWorkflowTask", + ) + require.NoError(s.T(), res.Err) + s.awaitNextWorkflow(searchAttr) + s.Equal(2, wfExecutions, "Should re-executed the workflow") + s.Equal(1, activityExecutions, "Should not have re-executed the activity") +} + func (s *SharedServerSuite) TestWorkflow_Reset_ToEventID() { // We execute two activities and will resume just before the second one. We use the same activity for both // but a unique input so we can check which fake activity is executed @@ -248,6 +332,94 @@ func (s *SharedServerSuite) TestBatchResetByBuildId() { sut.stopWorkerFor("v3") } +func (s *SharedServerSuite) TestWorkflow_ResetBatch_OnlyMatchingQuery() { + var resetWfExecutions, resetActivityExecutions int + var nonResetWfExecutions, nonResetActivityExecutions int + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + isReset, ok := a.(bool) + if !ok { + return nil, fmt.Errorf("expected bool, not %T (%v)", a, a) + } + if isReset { + resetActivityExecutions++ + } else { + nonResetActivityExecutions++ + } + return nil, nil + }) + s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) { + workflow.ExecuteActivity(ctx, DevActivity, a).Get(ctx, nil) + isReset, ok := a.(bool) + if !ok { + return nil, fmt.Errorf("expected bool, not %T (%v)", a, a) + } + if isReset { + resetWfExecutions++ + } else { + nonResetWfExecutions++ + } + return nil, nil + }) + + resetSearchAttr := "keyword-" + uuid.NewString() + run, err := s.Client.ExecuteWorkflow( + s.Context, + client.StartWorkflowOptions{ + TaskQueue: s.Worker().Options.TaskQueue, + SearchAttributes: map[string]any{"CustomKeywordField": resetSearchAttr}, + }, + DevWorkflow, + true, + ) + s.NoError(err) + var junk any + s.NoError(run.Get(s.Context, &junk)) + s.Equal(1, resetWfExecutions) + + nonResetSearchAttr := "keyword-" + uuid.NewString() + nonResetRun, err := s.Client.ExecuteWorkflow( + s.Context, + client.StartWorkflowOptions{ + TaskQueue: s.Worker().Options.TaskQueue, + SearchAttributes: map[string]any{"CustomKeywordField": nonResetSearchAttr}, + }, + DevWorkflow, + false, + ) + s.NoError(err) + s.NoError(nonResetRun.Get(s.Context, &junk)) + s.Equal(1, nonResetWfExecutions) + + s.CommandHarness.Stdin.WriteString("y\n") + res := s.Execute( + "workflow", "reset", + "--address", s.Address(), + "--query", fmt.Sprintf("CustomKeywordField = '%s'", resetSearchAttr), + "-t", "FirstWorkflowTask", + "--reason", "test-reset-FirstWorkflowTask", + ) + require.NoError(s.T(), res.Err) + s.Eventually(func() bool { + resp, err := s.Client.ListWorkflow(s.Context, &workflowservice.ListWorkflowExecutionsRequest{ + Query: "CustomKeywordField = '" + resetSearchAttr + "'" + " OR " + "CustomKeywordField = '" + nonResetSearchAttr + "'", + }) + s.NoError(err) + if len(resp.Executions) != 3 { + return false + } + for _, exec := range resp.Executions { + if exec.Status != enums.WORKFLOW_EXECUTION_STATUS_COMPLETED { + return false + } + } + return true + }, 3*time.Second, 100*time.Millisecond) + s.Equal(2, resetWfExecutions, "Should have re-executed the workflow from the beginning") + s.Equal(2, resetActivityExecutions, "Should have re-executed the workflow from the beginning") + s.Equal(1, nonResetWfExecutions, "Should not have re-executed the non-matching workflow") + s.Equal(1, nonResetActivityExecutions, "Should not have re-executed the non-matching workflow") +} + type WorkflowResetTest struct { s *SharedServerSuite reapplyType string @@ -262,7 +434,16 @@ func (s *SharedServerSuite) TestWorkflow_Reset_DefaultReappliesAll() { expectUpdatesReapplied: true, expectSignalsReapplied: true, } - t.run() + t.runSingleReset() +} + +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ReappliesAll() { + t := WorkflowResetTest{ + s: s, + expectUpdatesReapplied: true, + expectSignalsReapplied: true, + } + t.runBatchReset() } func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeUpdate() { @@ -272,7 +453,17 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeUpdate() { expectUpdatesReapplied: false, expectSignalsReapplied: true, } - t.run() + t.runSingleReset() +} + +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ExcludeUpdate() { + t := WorkflowResetTest{ + s: s, + reapplyExclude: []string{"Update"}, + expectUpdatesReapplied: false, + expectSignalsReapplied: true, + } + t.runBatchReset() } func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeSignal() { @@ -282,7 +473,17 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeSignal() { expectUpdatesReapplied: true, expectSignalsReapplied: false, } - t.run() + t.runSingleReset() +} + +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ExcludeSignal() { + t := WorkflowResetTest{ + s: s, + reapplyExclude: []string{"Signal"}, + expectUpdatesReapplied: true, + expectSignalsReapplied: false, + } + t.runBatchReset() } func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeSignalAndUpdate() { @@ -292,7 +493,17 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ExcludeSignalAndUpdate() { expectUpdatesReapplied: false, expectSignalsReapplied: false, } - t.run() + t.runSingleReset() +} + +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ExcludeSignalAndUpdate() { + t := WorkflowResetTest{ + s: s, + reapplyExclude: []string{"Signal", "Update"}, + expectUpdatesReapplied: false, + expectSignalsReapplied: false, + } + t.runBatchReset() } func (s *SharedServerSuite) TestWorkflow_Reset_ReapplySignalOnly() { @@ -302,13 +513,32 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ReapplySignalOnly() { expectUpdatesReapplied: false, expectSignalsReapplied: true, } - t.run() + t.runSingleReset() } -func (t *WorkflowResetTest) run() { +func (s *SharedServerSuite) TestWorkflow_ResetBatch_ReapplySignalOnly() { + t := WorkflowResetTest{ + s: s, + reapplyType: "Signal", + expectUpdatesReapplied: false, + expectSignalsReapplied: true, + } + t.runBatchReset() +} + +func (t *WorkflowResetTest) runSingleReset() { + t.run(false) +} + +func (t *WorkflowResetTest) runBatchReset() { + t.run(true) +} + +func (t *WorkflowResetTest) run(resetBatch bool) { s := t.s var wfExecutions, updateHandlerExecutions, signalHandlerExecutions int s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) { + // Handle signals sigChan := workflow.GetSignalChannel(ctx, "mySignal") workflow.Go(ctx, func(ctx workflow.Context) { @@ -333,9 +563,14 @@ func (t *WorkflowResetTest) run() { searchAttr := "keyword-" + uuid.NewString() run := t.startWorkflowAndSendTwoSignalsAndTwoUpdates(searchAttr) s.Equal(2, updateHandlerExecutions) + s.Equal(2, signalHandlerExecutions) s.Equal(1, wfExecutions) - t.resetWorkflow(run.GetID()) + if resetBatch { + t.resetBatchWorkflow(searchAttr) + } else { + t.resetWorkflow(run.GetID()) + } s.awaitNextWorkflow(searchAttr) if t.expectUpdatesReapplied { @@ -365,8 +600,11 @@ func (t *WorkflowResetTest) startWorkflowAndSendTwoSignalsAndTwoUpdates(searchAt ) s.NoError(err) + // We send the updates before the signals in order to ensure that no signal + // enters history before the first WorkflowTaskCompleted. This is necessary + // because there are tests that reset to FirstWorkflowTask, and assume that + // all signals are received after that event. for i := 1; i <= 2; i++ { - s.NoError(s.Client.SignalWorkflow(s.Context, run.GetID(), run.GetRunID(), "mySignal", fmt.Sprintf("%d", i))) updateHandle, err := s.Client.UpdateWorkflow(s.Context, client.UpdateWorkflowOptions{ WorkflowID: run.GetID(), RunID: run.GetRunID(), @@ -375,6 +613,7 @@ func (t *WorkflowResetTest) startWorkflowAndSendTwoSignalsAndTwoUpdates(searchAt }) s.NoError(err) s.NoError(updateHandle.Get(s.Context, nil)) + s.NoError(s.Client.SignalWorkflow(s.Context, run.GetID(), run.GetRunID(), "mySignal", fmt.Sprintf("%d", i))) } s.NoError(run.Get(s.Context, nil)) return run @@ -405,6 +644,31 @@ func (t *WorkflowResetTest) resetWorkflow(workflowID string) { require.NoError(s.T(), res.Err) } +func (t *WorkflowResetTest) resetBatchWorkflow(searchAttr string) { + s := t.s + args := []string{ + "workflow", "reset", + "--address", s.Address(), + "--query", fmt.Sprintf("CustomKeywordField = '%s'", searchAttr), + "--type", "FirstWorkflowTask", + "--reason", "test-workflow-reset", + } + if len(t.reapplyExclude) > 0 && t.reapplyType != "" { + panic("--reapply-type cannot be used with --reapply-exclude") + } + if t.reapplyType != "" { + args = append(args, "--reapply-type", t.reapplyType) + } + if len(t.reapplyExclude) > 0 { + for _, exclude := range t.reapplyExclude { + args = append(args, "--reapply-exclude", exclude) + } + } + s.CommandHarness.Stdin.WriteString("y\n") + res := s.Execute(args...) + require.NoError(s.T(), res.Err) +} + func (s *SharedServerSuite) TestWorkflow_Reset_DoesNotAllowBothReapplyOptions() { res := s.Execute( "workflow", "reset", diff --git a/temporalcli/commands_test.go b/temporalcli/commands_test.go index d1000eb6..5f8f1e88 100644 --- a/temporalcli/commands_test.go +++ b/temporalcli/commands_test.go @@ -600,3 +600,9 @@ func TestUnknownCommandExitsNonzero(t *testing.T) { res := commandHarness.Execute("blerkflow") assert.Contains(t, res.Err.Error(), "unknown command") } + +func (s *SharedServerSuite) TestHiddenAliasLogFormat() { + _ = s.waitActivityStarted().GetID() + res := s.Execute("workflow", "list", "--log-format", "pretty", "--address", s.Address()) + s.NoError(res.Err) +} diff --git a/temporalcli/commandsgen/code.go b/temporalcli/commandsgen/code.go index 604609d1..5c10057b 100644 --- a/temporalcli/commandsgen/code.go +++ b/temporalcli/commandsgen/code.go @@ -359,10 +359,14 @@ func (o *Option) writeFlagBuilding(selfVar, flagVar string, w *codeWriter) error return fmt.Errorf("missing enum values") } // Create enum - pieces := make([]string, len(o.EnumValues)) + pieces := make([]string, len(o.EnumValues)+len(o.HiddenLegacyValues)) for i, enumVal := range o.EnumValues { pieces[i] = fmt.Sprintf("%q", enumVal) } + for i, legacyVal := range o.HiddenLegacyValues { + pieces[i+len(o.EnumValues)] = fmt.Sprintf("%q", legacyVal) + } + w.writeLinef("%v.%v = NewStringEnum([]string{%v}, %q)", selfVar, o.fieldName(), strings.Join(pieces, ", "), o.Default) flagMeth = "Var" @@ -371,10 +375,13 @@ func (o *Option) writeFlagBuilding(selfVar, flagVar string, w *codeWriter) error return fmt.Errorf("missing enum values") } // Create enum - pieces := make([]string, len(o.EnumValues)) + pieces := make([]string, len(o.EnumValues)+len(o.HiddenLegacyValues)) for i, enumVal := range o.EnumValues { pieces[i] = fmt.Sprintf("%q", enumVal) } + for i, legacyVal := range o.HiddenLegacyValues { + pieces[i+len(o.EnumValues)] = fmt.Sprintf("%q", legacyVal) + } if o.Default != "" { w.writeLinef("%v.%v = NewStringEnumArray([]string{%v}, %q)", diff --git a/temporalcli/commandsgen/commands.yml b/temporalcli/commandsgen/commands.yml index 516a4e5e..5340be8b 100644 --- a/temporalcli/commandsgen/commands.yml +++ b/temporalcli/commandsgen/commands.yml @@ -161,10 +161,13 @@ commands: Default is "info" for most commands and "warn" for `server start-dev`. default: info - name: log-format - type: string - description: | - Log format. - Options are: text, json. + type: string-enum + description: Log format. + enum-values: + - text + - json + hidden-legacy-values: + - pretty default: text - name: output type: string-enum @@ -314,8 +317,8 @@ commands: | | | Please note: | | - Wrap attributes with backticks if it contains characters not in | - | `[a-zA-Z0-9]`. | - | - `STARTS_WITH` is only available for Keyword search attributes. | + | [a-zA-Z0-9]. | + | - STARTS_WITH is only available for Keyword search attributes. | +----------------------------------------------------------------------------+ ``` @@ -3331,4 +3334,4 @@ option-sets: description: | An external Nexus Endpoint that receives forwarded Nexus requests. May be used as an alternative to `--target-namespace` and - `--target-task-queue`. \ No newline at end of file + `--target-task-queue`. diff --git a/temporalcli/commandsgen/parse.go b/temporalcli/commandsgen/parse.go index f4d4657f..25cebfa8 100644 --- a/temporalcli/commandsgen/parse.go +++ b/temporalcli/commandsgen/parse.go @@ -20,16 +20,17 @@ var CommandsYAML []byte type ( // Option represents the structure of an option within option sets. Option struct { - Name string `yaml:"name"` - Type string `yaml:"type"` - Description string `yaml:"description"` - Short string `yaml:"short,omitempty"` - Default string `yaml:"default,omitempty"` - Env string `yaml:"env,omitempty"` - Required bool `yaml:"required,omitempty"` - Aliases []string `yaml:"aliases,omitempty"` - EnumValues []string `yaml:"enum-values,omitempty"` - Experimental bool `yaml:"experimental,omitempty"` + Name string `yaml:"name"` + Type string `yaml:"type"` + Description string `yaml:"description"` + Short string `yaml:"short,omitempty"` + Default string `yaml:"default,omitempty"` + Env string `yaml:"env,omitempty"` + Required bool `yaml:"required,omitempty"` + Aliases []string `yaml:"aliases,omitempty"` + EnumValues []string `yaml:"enum-values,omitempty"` + Experimental bool `yaml:"experimental,omitempty"` + HiddenLegacyValues []string `yaml:"hidden-legacy-values,omitempty"` } // Command represents the structure of each command in the commands map.