Repository: kubeflow/kfp-tekton (language: python)

Issue:
Enhance AnySequencer to make it an op
Enhance AnySequencer to make it an container op with name which is easier to reuse

**Which issue is resolved by this Pull Request:** 
Because Any Sequencer is created implicitly, by applying after_any function to another op. There are two problems here:

- any-sequencers can get no name or other user-defined metadata
- each op needs its own any-sequencer, even if it's identical to another one

I'd suggest to make it an op instead (dsl.AfterAny? dsl.AnySequencer?), and make after_any a simple utility function which creates a new after-any op and sets a dependency on it to the argument op.




Discussion / hints:
/assign @jinchihe @fenglixa 
Thanks @gang, for the PR. the CI test failed, seems some `license header` was not added caused it. 
You can run `make lint` before commit to check what's the problem
And it can be easily reused if there's multiple tasks depend on the any sequencer, for example task1 and task2 all depend on the AnySequencer:
```
seq = AnySequencer(
  [op0, op1],
  # naming the Any Sequencer, like any other op
  name="wait-for-any-file"
)
task1 = dsl.ContainerOp(
......
).after(seq)
task2 = dsl.ContainerOp(
......
).after(seq)
```
before merging this PR, just make sure to run the following commands to regenerate the tests and fix the python lint
```
make unit_test GENERATE_GOLDEN_YAML=True
make lint
make check_license
```
> before merging this PR, just make sure to run the following commands to regenerate the tests and fix the python lint
> 
> ```
> make unit_test GENERATE_GOLDEN_YAML=True
> make lint
> make check_license
> ```

Thanks Tommy, got it!
Thanks @pugangxa 
/lgtm
/approve
[APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubeflow/kfp-tekton/pull/499#issuecomment-800742652" title="Approved">fenglixa</a>*, *<a href="https://github.com/kubeflow/kfp-tekton/pull/499#" title="Author self-approved">pugangxa</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubeflow%2Fkfp-tekton).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubeflow/kfp-tekton/blob/master/OWNERS)~~ [fenglixa]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
@pugangxa Looks great, thanks Gang.

Fix patch:
diff --git a/sdk/FEATURES.md b/sdk/FEATURES.md
index 10c956d4de..e1dd52027e 100644
--- a/sdk/FEATURES.md
+++ b/sdk/FEATURES.md
@@ -128,7 +128,7 @@ The `finally` syntax is supported since Tekton version `0.14.0`.
 
 ### Pipeline Loops
 
-PipelineLoops is a feature for running a component or a set of component tasks multiple times in a loop. Right now, Tekton supports loop pipeline/tasks via an implementation of [Tekton Custom Tasks](https://github.com/tektoncd/community/blob/master/teps/0002-custom-tasks.md) controller named as "PipelineLoop". Please refer to the examples [here](/tekton-catalog/pipeline-loops/examples) to understand more details about the usage of loops. 
+PipelineLoops is a feature for running a component or a set of component tasks multiple times in a loop. Right now, Tekton supports loop pipeline/tasks via an implementation of [Tekton Custom Tasks Controller](https://github.com/tektoncd/community/blob/master/teps/0002-custom-tasks.md) named as "PipelineLoop". Please refer to the examples [here](/tekton-catalog/pipeline-loops/examples) to understand more details about the usage of loops.
 
 To use this feature, please ensure Tekton version >= v0.19, and "data.enable-custom-tasks" is "true" in feature-flags configmap:
 `kubectl edit cm feature-flags -n tekton-pipelines`
@@ -141,12 +141,12 @@ To see how the Python SDK provides this feature, refer to the examples below:
 
 ### Any Sequencer
 
-When any one of the task dependencies completes successfully, the dependent task will be started. Order of execution of the dependencies doesn’t matter, and the pipeline doesn't wait for all the task dependencies to complete before moving to the next step. Please follow the details of the implementation in the [design doc](https://docs.google.com/document/d/1oXOdiItI4GbEe_qzyBmMAqfLBjfYX1nM94WHY3EPa94/edit#heading=h.dt8bhna4spym). 
+When any one of the task dependencies completes successfully, the dependent task will be started. Order of execution of the dependencies doesn’t matter, and the pipeline doesn't wait for all the task dependencies to complete before moving to the next step. Please follow the details of the implementation in the [design doc](https://docs.google.com/document/d/1oXOdiItI4GbEe_qzyBmMAqfLBjfYX1nM94WHY3EPa94/edit#heading=h.dt8bhna4spym).
 
 For example:
 
 ```
-from kfp_tekton.dsl._any_seqencer import after_any
+from kfp_tekton.tekton import after_any
 
 dsl.ContainerOp(
   ...
diff --git a/sdk/python/kfp_tekton/dsl/_any_seqencer.py b/sdk/python/kfp_tekton/tekton.py
similarity index 81%
rename from sdk/python/kfp_tekton/dsl/_any_seqencer.py
rename to sdk/python/kfp_tekton/tekton.py
index ecf0e0a8d1..65a7c1f5ed 100644
--- a/sdk/python/kfp_tekton/dsl/_any_seqencer.py
+++ b/sdk/python/kfp_tekton/tekton.py
@@ -20,16 +20,16 @@
 
 
 class AnySequencer(ContainerOp):
-    """Represents an op present that will proceed when any denpendent condition met
+    """A containerOp that will proceed when any of the dependent containerOps completed
+       successfully
 
     Args:
-        name: the name of the op. It does not have to be unique within a pipeline
-            because the pipeline will generates a unique new name in case of conflicts.
+        name: The name of the containerOp. It does not have to be unique within a pipeline
+                because the pipeline will generate a unique new name in case of conflicts.
 
-        any: the list of `Sidecar` objects describing the sidecar containers to deploy
-                together with the `main` container.
+        any: List of `Conditional` containerOps that deploy together with the `main`
+                containerOp.
     """
-
     def __init__(self,
                  any: List[dsl.ContainerOp],
                  name: str = None,):


Test patch:
diff --git a/sdk/python/tests/compiler/testdata/any_sequencer.py b/sdk/python/tests/compiler/testdata/any_sequencer.py
index d85a6f09ef..8730f561ac 100644
--- a/sdk/python/tests/compiler/testdata/any_sequencer.py
+++ b/sdk/python/tests/compiler/testdata/any_sequencer.py
@@ -14,7 +14,7 @@
 
 from kfp import dsl
 from kfp_tekton.compiler import TektonCompiler
-from kfp_tekton.dsl._any_seqencer import after_any
+from kfp_tekton.tekton import after_any
 
 
 @dsl.pipeline(
@@ -50,7 +50,7 @@ def any_sequence_pipeline(
         command=["/bin/bash", "-c"],
         arguments=["sleep 30"]
     ).apply(after_any([task1, task2, task3], "any_test"))
-    
+
 
 if __name__ == "__main__":
     TektonCompiler().compile(any_sequence_pipeline, "any_sequencer" + ".yaml")