Bug 1349662: minor reorganizaiton of action documentation; r=jonasfj
authorDustin J. Mitchell <dustin@mozilla.com>
Wed, 22 Mar 2017 19:40:10 +0000
changeset 349312 4d277b10d10efb83af6e2f54a173e209ad3bab6a
parent 349311 b31c893d19a012af563970eca9f4eb4694a48ae0
child 349313 52a505ea3c6c85ea1774ec0decfdbead6e2e2c29
push id31550
push usercbook@mozilla.com
push dateFri, 24 Mar 2017 13:22:27 +0000
treeherdermozilla-central@473e0b201761 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonasfj
bugs1349662
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1349662: minor reorganizaiton of action documentation; r=jonasfj MozReview-Commit-ID: 9XZaOG9rF60
taskcluster/docs/action-details.rst
taskcluster/docs/action-spec.rst
taskcluster/docs/actions.rst
taskcluster/docs/in-tree-actions.rst
taskcluster/docs/index.rst
new file mode 100644
--- /dev/null
+++ b/taskcluster/docs/action-details.rst
@@ -0,0 +1,239 @@
+Action Task Implementation
+==========================
+
+This document shows how to define an action in-tree such that it shows up in
+supported user interfaces like Treeherder. For details on interface between
+in-tree logic and external user interfaces, see
+:doc:`the specification for actions.json <action-spec>`.
+
+There are two options for defining actions: creating a callback action, or
+creating a custom action task.  A callback action automatically defines an
+action task that will invoke a Python function of your devising.
+
+A custom action task is an arbitrary task definition that will be created
+directly.  In cases where the callback would simply call ``queue.createTask``,
+a custom action task can be more efficient.
+
+Creating a Callback Action
+--------------------------
+A *callback action* is an action that calls back into in-tree logic. That is,
+you register the action with title, description, context, input schema and a
+python callback. When the action is triggered in a user interface,
+input matching the schema is collected, passed to a new task which then calls
+your python callback, enabling it to do pretty much anything it wants to.
+
+To create a new action you must create a file
+``taskcluster/taskgraph/actions/my-action.py``, that at minimum contains::
+
+  from registry import register_callback_action
+
+  @register_callback_action(
+      title='Say Hello',
+      symbol='hw',  # Show the callback task in treeherder as 'hw'
+      description="Simple **proof-of-concept** callback action",
+      order=10000,  # Order in which it should appear relative to other actions
+  )
+  def hello_world_action(parameters, input, task_group_id, task_id, task):
+      # parameters is an instance of taskgraph.parameters.Parameters
+      # it carries decision task parameters from the original decision task.
+      # input, task_id, and task should all be None
+      print "Hello was triggered from taskGroupId: " + taskGroupId
+
+The example above defines an action that is available in the context-menu for
+the entire task-group (result-set or push in Treeherder terminology). To create
+an action that shows up in the context menu for a task we would specify the
+``context`` parameter.
+
+
+Setting the Action Context
+..........................
+The context parameter should be a list of tag-sets, such as
+``context=[{"platform": "linux"}]``, which will make the task show up in the
+context-menu for any task with ``task.tags.platform = 'linux'``. Below is
+some examples of context parameters and the resulting conditions on
+``task.tags`` (tags used below are just illustrative).
+
+``context=[{"platform": "linux"}]``:
+  Requires ``task.tags.platform = 'linux'``.
+``context=[{"kind": "test", "platform": "linux"}]``:
+  Requires ``task.tags.platform = 'linux'`` **and** ``task.tags.kind = 'test'``.
+``context=[{"kind": "test"}, {"platform": "linux"}]``:
+  Requires ``task.tags.platform = 'linux'`` **or** ``task.tags.kind = 'test'``.
+``context=[{}]``:
+  Requires nothing and the action will show up in the context menu for all tasks.
+``context=[]``:
+  Is the same as not setting the context parameter, which will make the action
+  show up in the context menu for the task-group.
+  (i.e., the action is not specific to some task)
+
+The example action below will be shown in the context-menu for tasks with
+``task.tags.platform = 'linux'``::
+
+  from registry import register_callback_action
+
+  @register_callback_action(
+      title='Retrigger',
+      symbol='re-c',  # Show the callback task in treeherder as 're-c'
+      description="Create a clone of the task",
+      order=1,
+      context=[{'platform': 'linux'}]
+  )
+  def retrigger_action(parameters, input, task_group_id, task_id, task):
+      # input will be None
+      print "Retriggering: {}".format(task_id)
+      print "task definition: {}".format(task)
+
+When the ``context`` parameter is set, the ``task_id`` and ``task`` parameters
+will provided to the callback. In this case the ``task_id`` and ``task``
+parameters will be the ``taskId`` and *task definition* of the task from whose
+context-menu the action was triggered.
+
+Typically, the ``context`` parameter is used for actions that operate on
+tasks, such as retriggering, running a specific test case, creating a loaner,
+bisection, etc. You can think of the context as a place the action should
+appear, but it's also very much a form of input the action can use.
+
+
+Specifying an Input Schema
+..........................
+In call examples so far the ``input`` parameter for the callbacks has been
+``None``. To make an action that takes input you must specify an input schema.
+This is done by passing a JSON schema as the ``schema`` parameter.
+
+When designing a schema for the input it is important to exploit as many of the
+JSON schema validation features as reasonably possible. Furthermore, it is
+*strongly* encouraged that the ``title`` and ``description`` properties in
+JSON schemas is used to provide a detailed explanation of what the input
+value will do. Authors can reasonably expect JSON schema ``description``
+properties to be rendered as markdown before being presented.
+
+The example below illustrates how to specify an input schema. Notice that while
+this example doesn't specify a ``context`` it is perfectly legal to specify
+both ``input`` and ``context``::
+
+  from registry import register_callback_action
+
+  @register_callback_action(
+      title='Run All Tasks',
+      symbol='ra-c',  # Show the callback task in treeherder as 'ra-c'
+      description="**Run all tasks** that have been _optimized_ away.",
+      order=1,
+      input={
+          'title': 'Action Options',
+          'description': 'Options for how you wish to run all tasks',
+          'properties': {
+              'priority': {
+                  'title': 'priority'
+                  'description': 'Priority that should be given to the tasks',
+                  'type': 'string',
+                  'enum': ['low', 'normal', 'high'],
+                  'default': 'low',
+              },
+              'runTalos': {
+                  'title': 'Run Talos'
+                  'description': 'Do you wish to also include talos tasks?',
+                  'type': 'boolean',
+                  'default': 'false',
+              }
+          },
+          'required': ['priority', 'runTalos'],
+          'additionalProperties': False,
+      },
+  )
+  def retrigger_action(parameters, input, task_group_id, task_id, task):
+      print "Create all pruned tasks with priority: {}".format(input['priority'])
+      if input['runTalos']:
+          print "Also running talos jobs..."
+
+When the ``schema`` parameter is given the callback will always be called with
+an ``input`` parameter that satisfies the previously given JSON schema.
+It is encouraged to set ``additionalProperties: false``, as well as specifying
+all properties as ``required`` in the JSON schema. Furthermore, it's good
+practice to provide ``default`` values for properties, as user interface generators
+will often take advantage of such properties.
+
+Once you have specified input and context as applicable for your action you can
+do pretty much anything you want from within your callback. Whether you want
+to create one or more tasks or run a specific piece of code like a test.
+
+Conditional Availability
+........................
+The decision parameters ``taskgraph.parameters.Parameters`` passed to
+the callback are also available when the decision task generates the list of
+actions to be displayed in the user interface. When registering an action
+callback the ``availability`` option can be used to specify a callable
+which, given the decision parameters, determines if the action should be available.
+The feature is illustrated below::
+
+  from registry import register_callback_action
+
+  @register_callback_action(
+      title='Say Hello',
+      symbol='hw',  # Show the callback task in treeherder as 'hw'
+      description="Simple **proof-of-concept** callback action",
+      order=2,
+      # Define an action that is only included if this is a push to try
+      available=lambda parameters: parameters.get('project', None) == 'try',
+  )
+  def try_only_action(parameters, input, task_group_id, task_id, task):
+      print "My try-only action"
+
+Properties of ``parameters``  are documented in the
+:doc:`parameters section <parameters>`. You can also examine the
+``parameters.yml`` artifact created by decisions tasks.
+
+
+Creating a Custom Action Task
+------------------------------
+
+It is possible to define an action that doesn't take a callback. Instead, you'll
+then have to provide a task template. For details on how the task template
+language works refer to :doc:`the specification for actions.json <action-spec>`,
+the example below illustrates how to create such an action::
+
+  from registry import register_task_action
+
+  @register_task_action(
+      title='Retrigger',
+      description="Create a clone of the task",
+      order=1,
+      context=[{'platform': 'linux'}],
+      input={
+          'title': 'priority'
+          'description': 'Priority that should be given to the tasks',
+          'type': 'string',
+          'enum': ['low', 'normal', 'high'],
+          'default': 'low',
+      },
+  def task_template_builder(parameters):
+      # The task template builder may return None to signal that the action
+      # isn't available.
+      if parameters.get('project', None) != 'try':
+        return None
+      return {
+          'created': {'$fromNow': ''},
+          'deadline': {'$fromNow': '1 hour'},
+          'expires': {'$fromNow': '14 days'},
+          'provisionerId': '...',
+          'workerType': '...',
+          'priority': '${input}',
+          'payload': {
+              'command': '...',
+              'env': {
+                  'TASK_DEFINITION': {'$json': {'eval': 'task'}}
+              },
+              ...
+          },
+          # It's now your responsibility to include treeherder routes, as well
+          # additional metadata for treeherder in task.extra.treeherder.
+          ...
+      },
+  )
+
+This kind of action is useful for creating simple derivative tasks, but is
+limited by the expressiveness of the template language. On the other hand, it
+is more efficient than an action callback as it does not involve an
+intermediate action task before creating the task the user requested.
+
+For further details on the template language, see :doc:`the specification for
+actions.json <action-spec>`.
--- a/taskcluster/docs/action-spec.rst
+++ b/taskcluster/docs/action-spec.rst
@@ -1,48 +1,48 @@
 Action Specification
 ====================
 This document specifies how actions exposed by the *decision task* are to be
 presented and triggered from Treeherder, or similar user interfaces.
 
 The *decision task* creates an artifact ``public/actions.json`` to be consumed
-by a user interface such as Treeherder. The `public/actions.json`` file
+by a user interface such as Treeherder. The ``public/actions.json`` file
 specifies actions that can be triggered such as:
 
  * Retrigger a task,
  * Retry specific test cases many times,
  * Obtain a loaner machine,
  * Back-fill missing tasks,
  * ...
 
 Through the ``public/actions.json`` file it is possible expose actions defined
 in-tree such that the actions can be conveniently triggered in Treeherder.
 This has two purposes:
 
  1. Facilitate development of utility actions/tools in-tree, and,
  2. Strongly decouple build/test configuration from Treeherder.
 
 For details on how define custom actions in-tree, refer to
-:doc:`the in-tree actions section <in-tree-actions>`, this document merely
+:doc:`the in-tree actions section <action-details>`. This document merely
 specifies how ``actions.json`` shall be interpreted.
 
 
 Specification of Actions
 ------------------------
 The *decision task* creates an artifact ``public/actions.json`` which contains
 a list of actions to be presented in the user-interface.
 
 
 Variables
 ---------
 The ``public/actions.json`` artifact has a ``variables`` property that is a
 mapping from variable names to JSON values to be used as constants.
 These variables can be referenced from task templates, but beware that they
 may overshadow builtin variables. This is mainly useful to deduplicate commonly
-used values, in-order to reduce template size, this features does not
+used values, in order to reduce template size. This feature does not
 introduce further expressiveness.
 
 
 MetaData
 --------
 Each action entry must define a ``title``, ``description`` and ``kind``,
 furthermore, the list of actions should be sorted by the order in which actions
 should appear in a menu.
@@ -58,17 +58,17 @@ simple formatting to explain what the ac
 
 The ``kind`` property specifies what kind of action the entry defines.
 At present only one kind of action is supported, the ``task`` kind.
 See section on *Action Kind: ``task``* below for details.
 
 
 Action Context
 --------------
-Few actions are relevant in all contexts, for this reason each action specifies
+Few actions are relevant in all contexts. For this reason each action specifies
 a ``context`` property. This property specifies when an action is relevant.
 Actions *relevant* for a task should be displayed in a context menu for the
 given task. Similarly actions *not relevant* for a given task, should not be
 display in the context menu for the given task.
 
 As a special case we say that actions for which *no relevant* contexts can
 exist, are *relevant* for the task-group. This could for example be an action
 to create tasks that was optimized away.
@@ -119,17 +119,17 @@ specified with by the action's ``schema`
 User interfaces for triggering actions, like Treeherder, are expected to provide
 JSON input that satisfies this schema. These interfaces are also expected to
 validate the input against the schema before attempting to trigger the action.
 
 It is expected that such user interfaces will attempt to auto-generate HTML
 forms from JSON schema specified. However, a user-interface implementor may also
 decide to hand write an HTML form for a particularly common or complex JSON
 schema. As long as the input generated from the form conforms to the schema
-specified for the given action. To ensure that implements should do a deep
+specified for the given action. To ensure that, implementers should do a deep
 comparison between a schema for which a hand-written HTML form exists, and the
 schema required by the action.
 
 It is perfectly legal to reference external schemas using
 constructs like ``{"$ref": "https://example.com/my-schema.json"}``, in this case
 it however strongly recommended that the external resource is available over
 HTTPS and allows CORS requests from any source.
 
@@ -139,24 +139,26 @@ use these when applicable.
 
 When writing schemas it is strongly encouraged that the JSON schema
 ``description`` properties are used to provide detailed descriptions. It is
 assumed that consumers will render these ``description`` properties as markdown.
 
 
 Action Kind: ``task``
 ---------------------
-An action with ``kind: 'task'`` is backed by an action task. That is when
-triggered the action creates a new task, and this is the result of the task.
-The task created by the action, may be useful in its own right, or it may
-simplify trigger in-tree scripts that creates new tasks. This way in-tree
-scripts can be triggered to execute complicated actions such as backfilling.
+
+An action with ``kind: 'task'`` is backed by an action task. That is, when the
+action is triggered by the user, the usre interface creates a new task,
+referred to as an *action task*.  The task created by the action may be useful
+in its own right, or it may simplify trigger in-tree scripts that create new
+tasks, similar to a decision task. This way in-tree scripts can be triggered to
+execute complicated actions such as backfilling.
 
 Actions of the ``'task'`` *kind* **must** have a ``task`` property. This
-property specifies the task template to be parameterized and created in-order
+property specifies the task template to be parameterized and created in order
 to trigger the action.
 
 The template is parameterized with the following variables:
 
 ``taskGroupId``
   the ``taskGroupId`` of task-group this is triggerd from,
 ``taskId``
   the ``taskId`` of the selected task, ``null`` if no task is
@@ -182,17 +184,18 @@ 3. Replacing objects on the form ``{$fro
 4. Replacing any object on the form ``{$json: value}`` with the
    value of ``JSON.stringify(result)`` where ``result`` is the result
    of recursive application of rules 1-4 on `value`.
 
 .. warning::
   The template language is currently under active development and additional
   features will be added in the future. Once feature complete the template
   language will be frozen to avoid breaking backwards compatibility for user
-  interface implementors.
+  interface implementors. See `JSON-E <https://github.com/taskcluster/json-e>`_
+  for details.
 
 The following **example** demonstrates how a task template can specify
 timestamps and dump input JSON into environment variables::
 
   {
     "workerType": "my-worker",
     "payload": {
       "created": {"$fromNow": ""},
new file mode 100644
--- /dev/null
+++ b/taskcluster/docs/actions.rst
@@ -0,0 +1,28 @@
+Actions
+=======
+
+This section shows how to define an action in-tree such that it shows up in
+supported user interfaces like Treeherder.
+
+At a very high level, the process looks like this:
+
+ * The decision task produces an artifact indicating what actions are
+   available.
+
+ * The user interface consults that artifact and presents appropriate choices
+   to the user, possibly involving gathering additional data from the user,
+   such as the number of times to re-trigger a test case.
+
+ * The user interface follows the action description to carry out the action.
+   In most cases (``action.kind == 'task'``), that entails creating an "action
+   task", including the provided information. That action task is responsible
+   for carrying out the named action, and may create new sub-tasks if necessary
+   (for example, to re-trigger a task).
+
+For details on interface between in-tree logic and external user interfaces,
+see :doc:`the specification for actions.json <action-spec>`.
+
+.. toctree::
+
+    action-details
+    action-spec
deleted file mode 100644
--- a/taskcluster/docs/in-tree-actions.rst
+++ /dev/null
@@ -1,229 +0,0 @@
-Writing Treeherder Actions in-tree
-==================================
-This document shows how to define an action in-tree such that it shows up in
-supported user interfaces like Treeherder. For details on interface between
-in-tree logic and external user interfaces, see
-:doc:`the specification for actions.json <action-spec>`.
-
-
-Creating a Callback Action
---------------------------
-A *callback action* is an action that calls back into in-tree logic. That is
-you register the action with title, description, context, input schema and a
-python callback. When the action is triggered in a user interface,
-input matching the schema is collected, passed to a new task which then calls
-your python callback, enabling it to do pretty much anything it wants to.
-
-To create a new action you must create a file
-``/taskcluster/actions/my-action.py``, that at minimum contains::
-
-  from registry import register_callback_action
-
-  @register_callback_action(
-      title='Say Hello',
-      symbol='hw',  # Show the callback task in treeherder as 'hw'
-      description="Simple **proof-of-concept** callback action",
-      order=10000,  # Order in which it should appear relative to other actions
-  )
-  def hello_world_action(parameters, input, task_group_id, task_id, task):
-      # parameters is an instance of taskgraph.parameters.Parameters
-      # it carries decision task parameters from the original decision task.
-      # input, task_id, and task should all be None
-      print "Hello was triggered from taskGroupId: " + taskGroupId
-
-The example above defines an action that is available in the context-menu for
-the entire task-group (result-set or push in Treeherder terminology). To create
-an action that shows up in the context menu for a task we must specify the
-``context`` parameter.
-
-
-Setting the Action Context
---------------------------
-The context parameter should be a list of tag-sets, such as
-``context=[{"platform": "linux"}]``, which will make the task show up in the
-context-menu for any task with ``task.tags.platform = 'linux'``. Below is
-some examples of context parameters and the resulting conditions on
-``task.tags`` (tags used below are just illustrative).
-
-``context=[{"platform": "linux"}]``:
-  Requires ``task.tags.platform = 'linux'``.
-``context=[{"kind": "test", "platform": "linux"}]``:
-  Requires ``task.tags.platform = 'linux'`` **and** ``task.tags.kind = 'test'``.
-``context=[{"kind": "test"}, {"platform": "linux"}]``:
-  Requires ``task.tags.platform = 'linux'`` **or** ``task.tags.kind = 'test'``.
-``context=[{}]``:
-  Requires nothing and the action will show up in the context menu for all tasks.
-``context=[]``:
-  Is the same as not setting the context parameter, which will make the action
-  show up in the context menu for the task-group.
-  (ie. the action is not specific to some task)
-
-The example action below will be shown in the context-menu for tasks with
-``task.tags.platform = 'linux'``::
-
-  from registry import register_callback_action
-
-  @register_callback_action(
-      title='Retrigger',
-      symbol='re-c',  # Show the callback task in treeherder as 're-c'
-      description="Create a clone of the task",
-      order=1,
-      context=[{'platform': 'linux'}]
-  )
-  def retrigger_action(parameters, input, task_group_id, task_id, task):
-      # input will be None
-      print "Retriggering: {}".format(task_id)
-      print "task definition: {}".format(task)
-
-When the ``context`` parameter is set, the ``task_id`` and ``task`` parameters
-will provided to the callback. In this case the ``task_id`` and ``task``
-parameters will be the ``taskId`` and *task definition* of the task from whose
-context-menu the action was triggered.
-
-Typically, the ``context`` parameter is used for actions that operates on
-tasks, such as retriggering, running a specific test case, creating a loaner,
-bisection, etc. You can think of the context as a place the action should
-appear, but it's also very much a form of input the action can use.
-
-
-Specifying an Input Schema
---------------------------
-In call examples so far the ``input`` parameter for the callback have been
-``None``, to make an action that takes input you must specify an input schema.
-This is done by passing a JSON schema as the ``schema`` parameter.
-
-When designing a schema for the input it is important to exploit as many of the
-JSON schema validation features as reasonably possible. Furthermore, it is
-*strongly* encouraged that the ``title`` and ``description`` properties in
-JSON schemas is used to provide a detailed explanation of what the input
-value will do. Authors can reasonably expect JSON schema ``description``
-properties to be rendered as markdown before being presented.
-
-The example below illustrates how to specify an input schema. Notice that while
-this example doesn't specify a ``context`` it is perfectly legal to specify
-both ``input`` and ``context``::
-
-  from registry import register_callback_action
-
-  @register_callback_action(
-      title='Run All Tasks',
-      symbol='ra-c',  # Show the callback task in treeherder as 'ra-c'
-      description="**Run all tasks** that have been _optimized_ away.",
-      order=1,
-      input={
-          'title': 'Action Options',
-          'description': 'Options for how you wish to run all tasks',
-          'properties': {
-              'priority': {
-                  'title': 'priority'
-                  'description': 'Priority that should be given to the tasks',
-                  'type': 'string',
-                  'enum': ['low', 'normal', 'high'],
-                  'default': 'low',
-              },
-              'runTalos': {
-                  'title': 'Run Talos'
-                  'description': 'Do you wish to also include talos tasks?',
-                  'type': 'boolean',
-                  'default': 'false',
-              }
-          },
-          'required': ['priority', 'runTalos'],
-          'additionalProperties': False,
-      },
-  )
-  def retrigger_action(parameters, input, task_group_id, task_id, task):
-      print "Create all pruned tasks with priority: {}".format(input['priority'])
-      if input['runTalos']:
-          print "Also running talos jobs..."
-
-When the ``schema`` parameter is given the callback will always be called with
-an ``input`` parameter that satisfies the previously given JSON schema.
-It is encouraged to set ``additionalProperties: false``, as well as specifying
-all properties as ``required`` in the JSON schema. Furthermore, it's good
-practice to provide ``default`` values for properties, user interface generators
-will often take advantage of such properties.
-
-Once you have specified input and context as applicable for your action you can
-do pretty much anything you want from within your callback. Whether you want
-to create one or more tasks or run a specific piece of code like a test.
-
-
-Conditional Availability
-------------------------
-The decision parameters ``taskgraph.parameters.Parameters`` passed to
-the callback is also available when the decision task generates the list of
-actions to be displayed in the user interface. When registering an action
-callback the ``availability`` parameter can be used to specify a lambda function
-that given the decision parameters determines if the action should be available.
-The feature is illustrated below::
-
-  from registry import register_callback_action
-
-  @register_callback_action(
-      title='Say Hello',
-      symbol='hw',  # Show the callback task in treeherder as 'hw'
-      description="Simple **proof-of-concept** callback action",
-      order=2,
-      # Define an action that is only included if this is a push to try
-      available=lambda parameters: parameters.get('project', None) == 'try',
-  )
-  def try_only_action(parameters, input, task_group_id, task_id, task):
-      print "My try-only action"
-
-Properties of ``parameters``  is documented in the
-:doc:`parameters section <parameters>`. You can also checkout the
-``parameters.yml`` artifact created by decisions tasks.
-
-
-Skipping the Action Callback
-----------------------------
-It is possible to define an action that doesn't take a callback, instead you'll
-then have to provide a task template. For details on how the task template
-language works refer to :doc:`the specification for actions.json <action-spec>`,
-the example below illustrates how to create such an action::
-
-  from registry import register_task_action
-
-  @register_task_action(
-      title='Retrigger',
-      description="Create a clone of the task",
-      order=1,
-      context=[{'platform': 'linux'}],
-      input={
-          'title': 'priority'
-          'description': 'Priority that should be given to the tasks',
-          'type': 'string',
-          'enum': ['low', 'normal', 'high'],
-          'default': 'low',
-      },
-  def task_template_builder(parameters):
-      # The task template builder may return None to signal that the action
-      # isn't available.
-      if parameters.get('project', None) != 'try':
-        return None
-      return {
-          'created': {'$fromNow': ''},
-          'deadline': {'$fromNow': '1 hour'},
-          'expires': {'$fromNow': '14 days'},
-          'provisionerId': '...',
-          'workerType': '...',
-          'priority': '${input}',
-          'payload': {
-              'command': '...',
-              'env': {
-                  'TASK_DEFINITION': {'$json': {'eval': 'task'}}
-              },
-              ...
-          },
-          # It's now your responsibility to include treeherder routes, as well
-          # additional metadata for treeherder in task.extra.treeherder.
-          ...
-      },
-  )
-
-This kind of actions is rarely useful due to the limited expressiveness of the
-template language. For further details on the template see
-:doc:`the specification for actions.json <action-spec>`. Obviously, this kind of
-action can be slightly more responsive because it doesn't create an intermediate
-task in-order to trigger a python callback inside the tree.
--- a/taskcluster/docs/index.rst
+++ b/taskcluster/docs/index.rst
@@ -23,12 +23,12 @@ check out the :doc:`how-to section <how-
 
     taskgraph
     loading
     transforms
     optimization
     yaml-templates
     docker-images
     cron
+    actions
+    action-spec
     how-tos
-    in-tree-actions
-    action-spec
     reference