Rules
A rule is a document plus a tree of operation nodes. In HCL it is one block per rule and one nested block per node.
pipeline "deploy-foo" {
name = "Deploy Foo"
desc = "Deploys foo"
when = "promote"
step "PRE" {
sh "Restart app" {
host = generic_server.alpha
run = "systemctl restart app"
capture = "restart_out"
timeout = 300
semaphore = "lock-a"
parallel = "fork"
on_error = "continue"
note = "be careful"
}
}
if "is prod" {
cond = "bl eq 'PROD'"
log "say it" {
msg = "hello"
level = "warn"
}
}
else {
perl "run perl" {
lang = "perl"
code = <<-EOT
my $x = 1;
return $x;
EOT
disabled = true
never_runs = true
}
}
wait "join" {}
}
Everything in an op block is one flat list: parameters and node modifiers side
by side, no data {} wrapper. host and run above are parameters of the sh
operation; capture, timeout, semaphore, parallel, on_error and note
are modifiers of the node. The parameters come first, in the order the
operation's dialog shows them, then the modifiers — see
Attribute order.
else is a sibling of if, not a child, because that is how the tree is
stored and the interpreter's adjacency rule depends on it. An else block that
is not directly after an if block fails to compile.
Rule types¶
| Keyword | rule_type |
Notes |
|---|---|---|
blueprint |
blueprint |
|
dashboard |
dashboard |
|
event |
event |
|
form |
form |
|
pipeline |
pipeline |
|
report_rule |
report |
the short report keyword belongs to the report CI |
rule |
independent |
|
workflow |
workflow |
|
ws |
webservice |
canonical |
webservice |
webservice |
accepted alias on input; ws is written |
independent "x" {} is HCL200 — independent is a type
name, not a keyword. A rule block whose keyword does not match the stored type
is HCL301 Not a rule block: 'foo'.
Rule addresses are <keyword>.<slug>: pipeline.deploy-foo, ws.upload,
rule.cleanup, report_rule.monthly.
Rule document attributes¶
The block label is the slug of the rule name and is mandatory — HCL302 A rule block needs a name label.
| Attribute | Stored field | Type | Written when |
|---|---|---|---|
name |
rule_name |
string | the real name does not slug to the label |
desc |
rule_desc |
string | set |
when |
rule_when |
string | set |
event |
rule_event |
string | set |
compile_mode |
rule_compile_mode |
string | set |
active |
rule_active |
bool | only when false |
subtype |
subtype |
string | set |
authtype |
authtype |
string | set |
wsdl |
wsdl |
string | set |
That is the complete vocabulary. Anything else is
HCL303 Unknown rule attribute 'foo' — a warning, and
the attribute is dropped.
Never written: id, _id, _uid, rule_seq, version_id, ts, username,
created_by, created_on, modified_by, modified_on.
A rule with no rule_name is skipped from export entirely.
Event rule scopes are not exported
An event rule stores scopes and scopes_raw, the filter that decides
which events it answers to. Neither is in the attribute list above, so an
exported event block loses its scope filter, and importing one writes
undef over whatever the target had. Export event rules with care.
Operation blocks¶
<keyword> "<label>" {
<parameters and modifiers, one flat list>
}
The label is free text — the human name the author gave the step. Spaces
and punctuation stay exactly as written; there is no slugging and no
validation. It is stored as the node's text attribute. An empty label is
written as no label at all, which is why else { and wait "join" {} look the
way they do. Only the first label is read.
An unknown keyword is HCL304 Unknown rule operation. The
node is dropped from the decoded tree and the rest of the rule decodes on, but
the diagnostic is an error, so cla import refuses the whole run with exit
2 before anything is planned. Nothing is silently written with a missing step.
A node with no operation key is skipped on export with warning HCL300.
Node modifiers¶
Sixteen names are modifiers of the node rather than parameters of the operation. They are the operation dialog's Options tab, plus the capture key and the note:
| HCL | Stored node attribute | Not written when | Notes |
|---|---|---|---|
capture |
data_key |
— | stash key to capture output into |
debug_mode |
debug_mode |
"none" |
"op" or "stash"; only "stash" compiles to anything, a stash dump before and after the step |
goto_label |
goto_label |
— | a label placed in front of the step's code |
needs_rollback |
needs_rollback_mode |
"none" |
"nb_after", "nb_before" or "nb_always" |
needs_rollback_key |
needs_rollback_key |
there is no needs_rollback |
the key the rollback is marked under |
node_stage |
stage |
— | marks the step as a stage of the job; see below for the spelling |
note |
note |
— | free text |
on_error |
error_trap |
"none" |
"none" is no trap, so writing it says nothing |
parallel |
parallel_mode |
"none" |
|
semaphore |
semaphore_key |
— | |
sub_name |
sub_name |
— | |
timeout |
timeout, or node_timeout |
— | see below |
trap_max_retry |
trap_max_retry |
0, or there is no on_error |
0 is unlimited |
trap_rollback |
trap_rollback |
true, or there is no on_error |
a boolean |
trap_timeout |
trap_timeout |
0, or there is no on_error |
seconds |
trap_timeout_action |
trap_timeout_action |
"abort", or there is no on_error |
"abort", "skip" or "retry" |
The dialog stores every Options field on every step it applies, so an
untouched step carries all of them at their defaults. Those defaults are what
"not written when" lists. A missing trap_* option beside an on_error
imports as that default, as the dialog would have stored it — a trap with no
trap_timeout_action times out into "abort". The other modifiers import as
unset, which the rule compiler reads the same as their default.
The tuning follows what it tunes. The trap_* options are written only
alongside an on_error, and needs_rollback_key only alongside a
needs_rollback, because the rule compiler reads them only there. A retry
count left on a step whose trap was switched back to "Throw Errors" has no
effect, and it is not exported:
sh "deploy" {
run = "make deploy"
on_error = "trap"
trap_timeout = 600
trap_timeout_action = "retry"
trap_max_retry = 3
trap_rollback = false
}
A name the operation declares as a parameter of its own belongs to the
operation. timeout on an http or web_request block is the request
timeout; the node's timeout is then spelled node_timeout:
http "call the api" {
url = "https://api.example.invalid/foo"
timeout = 10
node_timeout = 300
}
Both survive a round trip. A modifier is never allowed to shadow a parameter of the same name.
That protection covers the operations Clarive ships, whose parameters are known.
An operation added by an extension service is not in that list, so the stage is
always spelled node_stage: a service of that kind with a stage parameter of
its own keeps it, and the two never meet.
Run state¶
Four states, spelled as booleans. The default — active, runs in both directions — writes nothing.
| HCL | Stored | Meaning |
|---|---|---|
disabled = true |
active = 0 |
the step is off |
forward_only = true |
run_forward=1, run_rollback=0 |
|
rollback_only = true |
run_forward=0, run_rollback=1 |
|
never_runs = true |
run_forward=0, run_rollback=0 |
compiled as if(0) |
Conditions¶
A condition is stored as a row of indexed keys — operand_a[0], operator[0],
operand_b[0] — which are not even valid HCL identifiers. Four spellings cover
them:
if "one test" {
cond = "bl eq 'PROD'"
}
if "no right operand" {
cond = "bl is_empty"
}
if "several tests" {
all = ["bl eq 'PROD'", "status ne 'closed'"]
}
if "with options" {
cond = {
a = "bl"
op = "eq"
b = "prod"
ignore_case = true
}
}
| Spelling | Stored when |
Shape |
|---|---|---|
cond = "A op 'B'" |
all |
one row |
cond = "A op" |
all |
one row, empty right operand |
cond = { a, op, b, ... } |
all |
one row with options |
all = [...] |
all |
one row per element |
any = [...] |
any |
|
none = [...] |
none |
The flat string form is used when all three operands are plain scalars and
there are no options; otherwise the object form, whose keys are a, op and
b. A slot absent from the stored row stays absent rather than becoming
null. In the string form, ' and \ in the right operand are backslash
escaped.
An unreadable condition is HCL305.
cond, all, any and none are reserved on any node block, not just
if — any node can carry a condition, and they always decode into indexed
operand keys in that node's data.
Parameters¶
Everything not listed above is a parameter of the operation, written under the stored data key. For six operations the HCL name differs from the stored key, because the stored key is an internal spelling nobody would guess:
| Keyword | HCL name | Stored key |
|---|---|---|
log |
msg |
textInfo |
log |
level |
levelInfo |
sh |
run |
path |
sh |
host |
server |
ship |
from |
local_path |
ship |
to |
remote_path |
ship |
host |
server |
fetch |
from |
remote_path |
fetch |
to |
local_path |
fetch |
host |
server |
tar |
from |
source_dir |
tar |
to |
tarfile |
Every other operation uses its stored key verbatim.
The parameter set of an operation is open. There is no schema for it: an op
block accepts any attribute and writes it into the node's data. To find what
an operation actually accepts, in order of authority:
- the
dataandconfig_metaof itsregisterblock; - its rulebook contract, if it has one;
- the ExtJS form under
root/forms/that the registration points at — this is what the Rule Designer fills in, and therefore what a stored node carries; - the palette documentation for the op.
The defaults table below is derived from (3) and is the only part of the parameter set that is enumerated in code.
Attribute order¶
An exported op block reads the way its dialog does, top to bottom:
- parameters, in the order the operation's form lays its fields out —
letwritesvariablebefore theexprit is set to,shipthe host and user before the paths. An operation with no form follows the order of thedatadefaults its registration declares, soforeachwrites thevariableit walks before thelocal_vareach item lands in. A parameter the form does not show comes after the rest, alphabetically; - modifiers and run state, in the order of the dialog's Options tab —
disabled,capture,needs_rollback,needs_rollback_key, the run state (forward_only,rollback_only,never_runs),timeout,semaphore,parallel,debug_mode,on_errorand itstrap_*tuning,sub_name,node_stage— thengoto_labeland thenote.
let "SET EXPR" {
variable = "foo"
expr = "[1..int(rand(1)+2)]"
}
The form order is not read from the forms at export time. It is generated into
lib/Clarive/HCL/OpOrder.pm by bun script/hcl_op_order.js, which evaluates
every op form the way the dialog builds it, because most forms declare their
fields in one order and lay them out in another. Run it again after changing a
form; --check exits 1 when the table is out of date.
Order is only how a file is written. On import the attributes of a block may come in any order and mean the same.
Values¶
Parameters take any expression the language has: strings, heredocs, numbers,
booleans, lists, object literals, references and b64()/enc().
pipeline "foo" {
step "RUN" {
sh "shell" {
host = generic_server.alpha
run = <<-EOT
set -e
cd ${job_dir}/foo
make install
EOT
}
http "api" {
url = "https://api.example.invalid/foo"
headers = {
"Content-Type" : "application/json"
}
password = b64("aHVudGVyMg==")
}
call "CALL rule" {
id_rule = pipeline.foo-subrule
}
foreach "loop over baz" {
variable = "baz"
local_var = "current_baz"
let "set quux" {
variable = "quux"
expr = <<-PERL
my %h = %{ $stash->{foo} };
$h{bar};
PERL
}
}
}
}
A parameter whose name is sensitive — password, secret, token, api_key,
private_key, *webhook_url — goes through the same --secret policy as a
resource attribute. enc() without --secret-key is
HCL308; a wrong key is HCL309; an
unknown function is HCL306; wrong arity is
HCL307.
Addresses inside a rule's steps are resolved against the installation being
imported into. A step that ran on generic_server.alpha where it was exported
from runs on whatever that server is here, whatever id it happens to have.
What is stripped from a node¶
| Dropped | Why |
|---|---|
opid |
a per-install uuid that jobs and error traps key on; regenerated by the rule model on import |
icon, cls, leaf, expanded, iconCls, palette_area, checked |
Rule Designer presentation |
_id, created_on, created_by, modified_on, modified_by |
audit |
config when it is a hash |
the designer staples the registry's default data block onto every node it opens |
| any parameter sitting at its form default | see below |
Node bookkeeping is applied narrowly on purpose: username is not stripped
from a node's data, because service.web.rest has a real username parameter.
Operation registry echoes are not exported
sub_mode, closure, global_stash_keys and nested are not written.
They are not choices made in the dialog but copies of the operation's
registration, put on the node when it is dropped from the palette or
built by a rulebook. The rule compiler reads them, and an imported node
does not have them.
Form defaults¶
The Rule Designer saves every field of an operation's form whether or not anyone touched it, so a stored node carries values it was never given. A parameter sitting at what the form would have written is omitted; the import puts it back from the same table.
Absence means "the default". It never means "delete it".
--all-attributes on cla export turns the elision off. Use it for archives
and for files crossing a release boundary — the compact form reads back
identically only against the defaults table of the release that wrote it.
There is a worked before/after example using the ship operation at the end of
the cla export page.
The table is generated, not hand-maintained. Source:
lib/Clarive/HCL/OpDefaults.pm, rebuilt from the ExtJS forms under
root/forms/ and the register blocks that point at them by
.agent/hcl-audit/extract_form_defaults.js. It covers 117 operations, 69 of
which have at least one default; 160 default values in total.
Two things about the values:
- they are keyed by the stored data key, not the form field name, because that is what the encoder compares against;
- they are in the stored representation.
Cla.CBoxwrites'1'/'0'into a hidden input andExt.form.Checkboxwrites'on'or omits the key, so a comparison against a Perl boolean would never match anything.
Cla.ArrayGrid's default_value is deliberately absent from the table. It
seeds a newly added row, not the field; treating it as a default would drop a
real user-entered include = [".*"].
| Keyword | Registry key | Stored key | Default written by the form |
|---|---|---|---|
call |
statement.call |
id_rule |
"" |
catalog_if_var |
statement.catalog.if.var |
value |
"" |
catalog_if_var |
statement.catalog.if.var |
variable |
"" |
change_status |
service.topic.change_status |
back_to_origin |
(undef) |
change_status |
service.topic.change_status |
bypass_security |
(undef) |
change_status |
service.topic.change_status |
touch_parents |
0 |
changeset_natures |
service.changeset.natures |
commit_items |
(undef) |
ci_get_with_condition |
service.ci.get_with_condition |
instanciated_cis |
0 |
ci_get_with_condition |
service.ci.get_with_condition |
single |
0 |
ci_load_related |
service.ci.load_related |
depth |
1 |
ci_load_related |
service.ci.load_related |
mids_only |
0 |
ci_load_related |
service.ci.load_related |
query_type |
children |
ci_load_related |
service.ci.load_related |
single |
0 |
clone_repos |
service.changeset.checkout.top_revision_all |
depth |
1 |
db_deploy_sql |
service.db.deploy_sql |
comment |
strip |
db_deploy_sql |
service.db.deploy_sql |
error_mode |
fail |
db_deploy_sql |
service.db.deploy_sql |
exists_action |
drop |
db_deploy_sql |
service.db.deploy_sql |
mode |
direct |
db_deploy_sql |
service.db.deploy_sql |
split_mode |
auto |
db_deploy_sql |
service.db.deploy_sql |
split |
; |
db_deploy_sql |
service.db.deploy_sql |
transactional |
0 |
fail |
statement.fail |
allow_html |
(undef) |
fail |
statement.fail |
raw_message |
(undef) |
fileman_parse_config |
service.fileman.parse_config |
encoding |
utf8 |
fileman_parse_config |
service.fileman.parse_config |
type |
yaml |
fileman_store |
service.fileman.store |
store_data |
1 |
fileman_sync_remote |
service.fileman.sync_remote |
delete_extraneous |
(undef) |
fileman_write |
service.fileman.write |
body_encoding |
utf-8 |
fileman_write |
service.fileman.write |
file_encoding |
utf-8 |
fileman_write |
service.fileman.write |
line_endings |
original |
fileman_write |
service.fileman.write |
log_body |
no |
fileman_write |
service.fileman.write |
templating |
none |
fileman_write_config |
service.fileman.write_config |
encoding |
utf8 |
fileman_write_config |
service.fileman.write_config |
input_type |
var |
fileman_write_config |
service.fileman.write_config |
type |
yaml |
fileman_write_config |
service.fileman.write_config |
varname |
config_data |
fileman_write_remote |
service.fileman.write_remote |
backup_mode |
backup |
fileman_write_remote |
service.fileman.write_remote |
body_encoding |
utf-8 |
fileman_write_remote |
service.fileman.write_remote |
exist_mode_local |
skip |
fileman_write_remote |
service.fileman.write_remote |
exist_mode |
skip |
fileman_write_remote |
service.fileman.write_remote |
file_encoding |
utf-8 |
fileman_write_remote |
service.fileman.write_remote |
line_endings |
original |
fileman_write_remote |
service.fileman.write_remote |
log_body |
no |
fileman_write_remote |
service.fileman.write_remote |
rollback_mode |
rollback |
fileman_write_remote |
service.fileman.write_remote |
templating |
none |
git_create_branch |
service.git.create_branch |
force |
0 |
git_merge |
service.git.merge |
no_ff |
1 |
git_remove |
service.git.remove |
no_ff |
1 |
git_tag |
service.git.create_tag |
force |
0 |
git_timesync |
service.git.timesync |
path |
. |
http |
service.web.rest |
accept_any_cert |
0 |
http |
service.web.rest |
auto_parse |
1 |
http |
service.web.rest |
errors |
fail |
http |
service.web.rest |
method |
GET |
http |
service.web.rest |
timeout |
"" |
if_condition |
statement.if.condition |
condition |
"" |
if_condition |
statement.if.condition |
lang |
perl |
if_last_trap_action |
statement.if.last_trap_action |
job_trap_action |
skip |
if_not_var |
statement.if_not.var |
value |
"" |
if_not_var |
statement.if_not.var |
variable |
"" |
if_var |
statement.if.var |
value |
"" |
if_var |
statement.if.var |
variable |
"" |
if_var_list |
statement.if.var.list |
values |
"" |
if_var_list |
statement.if.var.list |
variable |
"" |
include |
statement.include |
id_rule |
"" |
job_create |
service.job.create |
job_type |
static |
job_pause |
service.job.pause |
no_fail |
0 |
job_set_rollbackable |
service.job.set_rollbackable |
rollbackable |
on |
job_system_messages |
service.job.system_messages |
expires |
24h |
log |
statement.log |
levelInfo |
info |
parsing_parse_files |
service.parsing.parse_files |
fail_mode |
skip |
perl |
statement.code.server |
lang |
js |
retry |
statement.retry |
attempts |
1 |
retry |
statement.retry |
pause |
0 |
rulebook_log |
statement.rulebook.log |
levelInfo |
info |
rulebook_run |
service.rulebook.run |
mode |
resources |
rulebook_shell |
service.rulebook.shell |
errors |
fail |
save_my_stats |
service.save_my_stats |
key |
rule.stats |
scripting_list_windows_services |
service.scripting.list_windows_services |
filter |
"" |
scripting_windows_service |
service.scripting.windows_service |
action |
start |
scripting_windows_service |
service.scripting.windows_service |
errors |
fail |
scripting_windows_service |
service.scripting.windows_service |
wait_timeout |
0 |
scripting_windows_service |
service.scripting.windows_service |
wait_until_status |
(undef) |
sed |
service.sed |
items_mode |
all_files |
sed |
service.sed |
slurp |
0 |
sed |
service.sed |
suffix |
"" |
service_fileman_foreach |
service.fileman.foreach |
dir_mode |
file_only |
service_fileman_foreach |
service.fileman.foreach |
path_mode |
files_flat |
service_fileman_foreach |
service.fileman.foreach |
relative_paths |
(undef) |
sh |
service.scripting.local |
errors |
fail |
sh |
service.scripting.remote |
errors |
fail |
ship |
service.fileman.ship |
anchor_path |
${job_dir}/${project} |
ship |
service.fileman.ship |
audit_tracked |
none |
ship |
service.fileman.ship |
backup_mode |
backup |
ship |
service.fileman.ship |
copy_attrs |
0 |
ship |
service.fileman.ship |
exist_mode_local |
skip |
ship |
service.fileman.ship |
exist_mode |
skip |
ship |
service.fileman.ship |
local_mode |
nature_items |
ship |
service.fileman.ship |
local_path |
${job_dir}/${project} |
ship |
service.fileman.ship |
recursive |
0 |
ship |
service.fileman.ship |
rel_path |
file_only |
ship |
service.fileman.ship |
rollback_mode |
rollback |
ship |
service.fileman.ship |
track_mode |
none |
shortcut |
statement.shortcut |
source_key |
"" |
statement_fileman_foreach |
statement.fileman.foreach |
dir_mode |
file_only |
statement_fileman_foreach |
statement.fileman.foreach |
path_mode |
files_flat |
statement_fileman_foreach |
statement.fileman.foreach |
relative_paths |
(undef) |
statement_if_nature |
statement.if.nature |
cut_path |
/ |
tar |
service.fileman.tar_nature |
clean_path_mode |
force |
tar |
service.fileman.tar_nature |
source_dir |
${job_dir}/${project} |
tar |
service.fileman.tar_nature |
tarfile |
${job_dir}/${job_name}_${project}.tar |
templating_transform |
service.templating.transform |
encoding |
utf-8 |
templating_transform |
service.templating.transform |
engine |
mason |
topic_calculate_effort |
service.topic.calculate_effort |
categories |
"" |
topic_calculate_effort |
service.topic.calculate_effort |
depth |
0 |
topic_calculate_effort |
service.topic.calculate_effort |
effort_type |
"" |
topic_calculate_effort |
service.topic.calculate_effort |
end_date |
"" |
topic_calculate_effort |
service.topic.calculate_effort |
init_date |
"" |
topic_calculate_effort |
service.topic.calculate_effort |
statuses |
"" |
topic_create |
service.topic.create |
bypass_security |
(undef) |
topic_create |
service.topic.create |
category |
"" |
topic_get_with_condition |
service.topic.get_with_condition |
not_in_status |
(undef) |
topic_related |
service.topic.related |
depth |
1 |
topic_related |
service.topic.related |
include_event_mid |
(undef) |
topic_related |
service.topic.related |
mid_only |
0 |
topic_related |
service.topic.related |
not_in_status |
(undef) |
topic_related |
service.topic.related |
query_type |
children |
topic_related |
service.topic.related |
related_categories |
"" |
topic_related |
service.topic.related |
related_status |
"" |
topic_related |
service.topic.related |
single |
0 |
topic_remove_file |
service.topic.remove_file |
asset_mid |
"" |
topic_remove_file |
service.topic.remove_file |
bypass_security |
(undef) |
topic_remove_file |
service.topic.remove_file |
fields |
"" |
topic_update |
service.topic.update |
touch_parents |
0 |
update_changesets |
service.changeset.update |
status_on_fail |
"" |
update_changesets |
service.changeset.update |
status_on_ok |
"" |
update_changesets |
service.changeset.update |
status_on_rollback_fail |
"" |
update_changesets |
service.changeset.update |
status_on_rollback_ok |
"" |
user_group_manage_roles |
service.user_group.manage_roles |
action |
assign |
user_load |
service.user.load |
mid_only |
0 |
user_manage_groups |
service.user.manage_groups |
action |
assign |
user_manage_roles |
service.user.manage_roles |
action |
assign |
var_push |
statement.var.push |
flatten |
1 |
var_push |
statement.var.push |
uniq |
1 |
var_set_jsexpr |
statement.var.set_jsexpr |
expr |
// enter js code here\n// variables in the stash are available as cla.stash("myvar")\n// the last line will be returned into the receiving variable\n\nparseInt(cla.stash("myvar")) + 1; |
var_set_jsexpr |
statement.var.set_jsexpr |
variable |
myvar |
wait |
statement.parallel.wait |
errors |
fail |
web_request |
service.web.request |
accept_any_cert |
(undef) |
web_request |
service.web.request |
body |
"" |
web_request |
service.web.request |
encoding |
utf-8 |
web_request |
service.web.request |
method |
GET |
web_request |
service.web.request |
timeout |
0 |
workflow_if_status_from |
statement.workflow.if_status_from |
statuses_from |
"" |
workflow_transition |
service.workflow.transition |
back_to_origin |
(undef) |
workflow_transition |
service.workflow.transition |
job_type |
"" |
workflow_transition |
service.workflow.transition |
statuses_to |
"" |
workflow_transition_match |
service.workflow.transition_match |
back_to_origin |
(undef) |
workflow_transition_match |
service.workflow.transition_match |
job_type |
"" |
workflow_transition_match |
service.workflow.transition_match |
statuses_from |
"" |
workflow_transition_match |
service.workflow.transition_match |
statuses_to |
"" |
Operation keywords¶
An operation's keyword comes from one of two places.
Curated. A hand-written table of 39 keywords covering 40 registry keys, in
lib/Clarive/HCL/RuleOps.pm. These are the ops people write by hand, and their
keywords are stable by contract.
Derived. Everything else gets an automatic keyword: strip a leading
service. or statement., join the remaining dot-segments with _, and
replace any character outside [A-Za-z0-9_] with _. Segment casing is not
changed, so service.genexus.buildRevision becomes genexus_buildRevision.
The table is generated from the registry, so it reflects the plugins this installation has loaded. To regenerate it:
cla exec perl -Ilib -e 'use Baseliner; Baseliner->build_app;
use Baseliner::Core::Registry; use Clarive::HCL::RuleOps;
printf "%-52s %s\n", $_, Clarive::HCL::RuleOps->alias_for_key($_)
for sort grep { /^(?:service|statement)\./ }
Baseliner::Core::Registry->starts_with("")'
The Form defaults column is the number of entries this operation has in
OpDefaults. The Imports back column is whether writing that keyword
produces the same registry key again.
Every operation reads back as itself
Each registry key has one keyword, and each keyword reads back as the key
it was written from — every one of the 319 operations registered when
this was last checked. The decoder does not reverse the
join '_' by guesswork: it looks the keyword up in an index built from the
registry. Where two keys would produce the same automatic keyword, both
keep their family segment and neither gets the bare spelling —
service.fileman.foreach and statement.fileman.foreach are
service_fileman_foreach and statement_fileman_foreach, and
statement.if.nature is statement_if_nature, because if_nature is the
curated keyword of statement.if.any_nature.
sh is the one keyword that stands for two keys: it is the remote shell
when a host is given and the local one otherwise.
if used to stand for all four IF operations and foreach for FOR eval
as well, and a file read every IF back as statement.if.var_condition
and every FOR eval as a FOREACH — a different operation each time, with
no diagnostic. The Rule Designer's HCL view saves what its text reads back
as, so a rule using them was changed, or no longer compiled, after an
untouched save. They have their own keywords now: if_var,
if_condition, if_var_list and perl_for. A file written before still
reads back right, by the parameters its blocks carry: an if with a
condition is an IF condition, with values an IF var in list, with a
variable an IF var; a foreach with code, varname or in_perl is a
FOR eval.
To check that every rule of an installation survives being written as HCL
and read back, run cla rule-check.
Curated keywords¶
| Keyword | Registry key | Form defaults | Imports back |
|---|---|---|---|
call |
statement.call |
1 | yes |
change_status |
service.topic.change_status |
3 | yes |
clone_repos |
service.changeset.checkout.top_revision_all |
1 | yes |
each_project |
statement.project.loop |
— | yes |
else |
statement.if.else |
— | yes |
elsif |
statement.if.elsif |
— | yes |
fail |
statement.fail |
2 | yes |
fetch |
service.fileman.retrieve |
— | yes |
foreach |
statement.foreach |
— | yes |
git_merge |
service.git.merge |
1 | yes |
git_rm_branch |
service.git.delete_reference |
— | yes |
git_tag |
service.git.create_tag |
1 | yes |
group |
statement.perl.group |
— | yes |
http |
service.web.rest |
5 | yes |
if |
statement.if.var_condition |
— | yes |
if_nature |
statement.if.any_nature |
— | yes |
include |
statement.include |
1 | yes |
init |
service.job.init |
— | yes |
let |
statement.var.set_expr |
— | yes |
load_items |
service.changeset.items |
— | yes |
log |
statement.log |
1 | yes |
perl |
statement.code.server |
1 | yes |
promote_baselines |
service.changeset.update_bls |
— | yes |
reply |
service.web.ws_response |
— | yes |
resource_create |
service.ci.create |
— | yes |
set |
statement.var.set |
— | yes |
sh |
service.scripting.local |
1 | yes |
sh |
service.scripting.remote |
1 | yes |
ship |
service.fileman.ship |
12 | yes |
slack |
service.slack.post_message |
— | yes |
sleep |
service.job.sleep |
— | yes |
step |
statement.step |
— | yes |
tar |
service.fileman.tar_nature |
3 | yes |
topic_create |
service.topic.create |
2 | yes |
topic_update |
service.topic.update |
1 | yes |
update_changesets |
service.changeset.update |
4 | yes |
wait |
statement.parallel.wait |
1 | yes |
web_request |
service.web.request |
5 | yes |
while |
statement.while |
— | yes |
A 40th curated entry, email, maps to service.notification.email. It is
absent from the table above because nothing registers that key — the only
mention of it anywhere in the tree is the alias table itself. Curated keywords
are not checked against the registry on decode, so an email block produces no
diagnostic: it decodes into a node pointing at an operation that does not
exist, and the rule fails when it is compiled. Do not use it.
Derived keywords¶
| Keyword | Registry key | Form defaults | Imports back |
|---|---|---|---|
amazon_change_region_task |
service.amazon_change_region.task |
— | yes |
amazon_generic_task |
service.amazon_generic.task |
— | yes |
amazon_instance_launcher_task |
service.amazon_instance_launcher.task |
— | yes |
amazon_instance_monitor_task |
service.amazon_instance_monitor.task |
— | yes |
amazon_instance_state_manager_task |
service.amazon_instance_state_manager.task |
— | yes |
approval_request |
service.approval.request |
— | yes |
artifactlocal_index_catalog |
service.artifactlocal.index_catalog |
— | yes |
artifacts_catalog_daemon |
service.artifacts.catalog_daemon |
— | yes |
artifacts_publish |
service.artifacts.publish |
— | yes |
auth_deny |
service.auth.deny |
— | yes |
auth_message |
service.auth.message |
— | yes |
auth_ok |
service.auth.ok |
— | yes |
blueprint_variable |
statement.blueprint.variable |
— | yes |
catalog_folder |
statement.catalog.folder |
— | yes |
catalog_form |
service.catalog.form |
— | yes |
catalog_if_var |
statement.catalog.if.var |
2 | yes |
catalog_step |
statement.catalog.step |
— | yes |
catch |
statement.catch |
— | yes |
changeset_checkout |
service.changeset.checkout |
— | yes |
changeset_checkout_bl |
service.changeset.checkout.bl |
— | yes |
changeset_checkout_bl_all_repos |
service.changeset.checkout.bl_all_repos |
— | yes |
changeset_natures |
service.changeset.natures |
1 | yes |
changeset_sync_baselines |
service.changeset.sync_baselines |
— | yes |
changeset_update_baselines |
service.changeset.update_baselines |
— | yes |
changeset_verify_revisions |
service.changeset.verify_revisions |
— | yes |
ci_get_with_condition |
service.ci.get_with_condition |
2 | yes |
ci_invoke |
service.ci.invoke |
— | yes |
ci_load |
service.ci.load |
— | yes |
ci_load_related |
service.ci.load_related |
4 | yes |
ci_update |
service.ci.update |
— | yes |
config |
service.config |
— | yes |
daemon_email |
service.daemon.email |
— | yes |
db_backup |
service.db.backup |
— | yes |
db_commit_all_transactions |
service.db.commit_all_transactions |
— | yes |
db_deploy_sql |
service.db.deploy_sql |
7 | yes |
db_rollback_all_transactions |
service.db.rollback_all_transactions |
— | yes |
dbi_connection_ping |
service.dbi_connection.ping |
— | yes |
delete_key |
statement.delete.key |
— | yes |
delete_trap_action |
statement.delete.trap_action |
— | yes |
dispatcher |
service.dispatcher |
— | yes |
do_while |
statement.do_while |
— | yes |
echo |
service.echo |
— | yes |
email_flush |
service.email.flush |
— | yes |
engine_parse |
service.engine.parse |
— | yes |
event_daemon |
service.event.daemon |
— | yes |
event_run_once |
service.event.run_once |
— | yes |
file_view_source |
service.file.view_source |
— | yes |
fileman_mkpath_remote |
service.fileman.mkpath_remote |
— | yes |
fileman_parse_config |
service.fileman.parse_config |
2 | yes |
fileman_rm |
service.fileman.rm |
— | yes |
fileman_rmtree |
service.fileman.rmtree |
— | yes |
fileman_store |
service.fileman.store |
1 | yes |
fileman_sync_remote |
service.fileman.sync_remote |
1 | yes |
fileman_tar |
service.fileman.tar |
— | yes |
fileman_write |
service.fileman.write |
5 | yes |
fileman_write_config |
service.fileman.write_config |
4 | yes |
fileman_write_remote |
service.fileman.write_remote |
9 | yes |
fileman_zip |
service.fileman.zip |
— | yes |
fileman_zip_nature |
service.fileman.zip_nature |
— | yes |
foreach_ci |
statement.foreach.ci |
— | yes |
foreach_split |
statement.foreach.split |
— | yes |
generic_server_connect |
service.generic_server.connect |
— | yes |
genexus_buildRevision |
service.genexus.buildRevision |
— | yes |
genexus_consolidateXPZ |
service.genexus.consolidateXPZ |
— | yes |
genexus_distributeObjects |
service.genexus.distributeObjects |
— | yes |
genexus_releaseRevision |
service.genexus.releaseRevision |
— | yes |
genexus_retrieveFiles |
service.genexus.retrieveFiles |
— | yes |
get_date |
service.get_date |
— | yes |
git_checkout |
service.git.checkout |
— | yes |
git_create_branch |
service.git.create_branch |
1 | yes |
git_job_elements |
service.git.job_elements |
— | yes |
git_link_revision_to_topic |
service.git.link_revision_to_topic |
— | yes |
git_newjob |
service.git.newjob |
— | yes |
git_rebase |
service.git.rebase |
— | yes |
git_remove |
service.git.remove |
1 | yes |
git_timesync |
service.git.timesync |
1 | yes |
gitrepository_create_tags |
service.gitrepository.create_tags |
— | yes |
grammar_parse |
service.grammar.parse |
— | yes |
if_any_bl |
statement.if.any_bl |
— | yes |
if_condition |
statement.if.condition |
2 | yes |
if_last_trap_action |
statement.if.last_trap_action |
1 | yes |
if_not_var |
statement.if_not.var |
2 | yes |
if_rollback |
statement.if.rollback |
— | yes |
if_var |
statement.if.var |
2 | yes |
if_var_list |
statement.if.var.list |
2 | yes |
imap_check_emails |
service.imap.check_emails |
— | yes |
job_create |
service.job.create |
1 | yes |
job_daemon |
service.job.daemon |
— | yes |
job_dummy |
service.job.dummy |
— | yes |
job_footprint |
service.job.footprint |
— | yes |
job_new |
service.job.new |
— | yes |
job_pause |
service.job.pause |
1 | yes |
job_rename_items |
service.job.rename_items |
— | yes |
job_run |
service.job.run |
— | yes |
job_set_rollbackable |
service.job.set_rollbackable |
1 | yes |
job_system_messages |
service.job.system_messages |
1 | yes |
ldap_search |
service.ldap.search |
— | yes |
let_merge |
statement.let.merge |
— | yes |
nature_block |
statement.nature.block |
— | yes |
nature_scan |
service.nature.scan |
— | yes |
nightly_build |
service.nightly_build |
— | yes |
notify_create |
service.notify.create |
— | yes |
parsing_parse_files |
service.parsing.parse_files |
1 | yes |
perl_code |
statement.perl.code |
— | yes |
perl_do |
statement.perl.do |
— | yes |
perl_eval |
statement.perl.eval |
— | yes |
perl_for |
statement.perl.for |
— | yes |
print |
service.print |
— | yes |
project_block |
statement.project.block |
— | yes |
project_scan |
service.project.scan |
— | yes |
purge_daemon |
service.purge.daemon |
— | yes |
purge_run_once |
service.purge.run_once |
— | yes |
restart_server |
service.restart_server |
— | yes |
retry |
statement.retry |
2 | yes |
root_cause_analysis_daemon |
service.root_cause_analysis.daemon |
— | yes |
rulebook_call_file |
statement.rulebook.call_file |
— | yes |
rulebook_define |
statement.rulebook.define |
— | yes |
rulebook_do |
statement.rulebook.do |
— | yes |
rulebook_export_vars |
statement.rulebook.export_vars |
— | yes |
rulebook_field_combo |
statement.rulebook.field_combo |
— | yes |
rulebook_field_date |
statement.rulebook.field_date |
— | yes |
rulebook_field_grid |
statement.rulebook.field_grid |
— | yes |
rulebook_field_pills |
statement.rulebook.field_pills |
— | yes |
rulebook_field_richtext |
statement.rulebook.field_richtext |
— | yes |
rulebook_field_text |
statement.rulebook.field_text |
— | yes |
rulebook_field_textarea |
statement.rulebook.field_textarea |
— | yes |
rulebook_field_time |
statement.rulebook.field_time |
— | yes |
rulebook_field_upload |
statement.rulebook.field_upload |
— | yes |
rulebook_foreach |
statement.rulebook.foreach |
— | yes |
rulebook_if |
statement.rulebook.if |
— | yes |
rulebook_image |
statement.rulebook.image |
— | yes |
rulebook_import_vars |
statement.rulebook.import_vars |
— | yes |
rulebook_index |
service.rulebook.index |
— | yes |
rulebook_literal |
statement.rulebook.literal |
— | yes |
rulebook_log |
statement.rulebook.log |
1 | yes |
rulebook_main |
statement.rulebook.main |
— | yes |
rulebook_readonly_fields |
statement.rulebook.readonly_fields |
— | yes |
rulebook_remove_fields |
statement.rulebook.remove_fields |
— | yes |
rulebook_return |
statement.rulebook.return |
— | yes |
rulebook_run |
service.rulebook.run |
1 | yes |
rulebook_run_import |
service.rulebook.run_import |
— | yes |
rulebook_set |
statement.rulebook.set |
— | yes |
rulebook_shell |
service.rulebook.shell |
1 | yes |
rulebook_try |
statement.rulebook.try |
— | yes |
rulebook_var |
statement.rulebook.var |
— | yes |
rulebook_web_response |
statement.rulebook.web_response |
— | yes |
rulebook_while |
statement.rulebook.while |
— | yes |
rulebook_write |
service.rulebook.write |
— | yes |
rulebookfile_index |
service.rulebookfile.index |
— | yes |
save_my_stats |
service.save_my_stats |
1 | yes |
scheduler |
service.scheduler |
— | yes |
scheduler_run_once |
service.scheduler.run_once |
— | yes |
scheduler_test |
service.scheduler.test |
— | yes |
script_run_script |
service.script.run_script |
— | yes |
scripting_list_windows_services |
service.scripting.list_windows_services |
1 | yes |
scripting_remote_eval |
service.scripting.remote_eval |
— | yes |
scripting_windows_service |
service.scripting.windows_service |
4 | yes |
sed |
service.sed |
3 | yes |
service_catalog_service |
service.catalog.service |
— | yes |
service_catalog_task |
service.catalog.task |
— | yes |
service_catalog_task_group |
service.catalog.task_group |
— | yes |
service_fail |
service.fail |
— | yes |
service_fileman_foreach |
service.fileman.foreach |
3 | yes |
shortcut |
statement.shortcut |
1 | yes |
sla_daemon |
service.sla.daemon |
— | yes |
snapshot_take |
service.snapshot.take |
— | yes |
stash_local |
statement.stash.local |
— | yes |
statement_catalog_service |
statement.catalog.service |
— | yes |
statement_catalog_task |
statement.catalog.task |
— | yes |
statement_catalog_task_group |
statement.catalog.task_group |
— | yes |
statement_fileman_foreach |
statement.fileman.foreach |
3 | yes |
statement_if_nature |
statement.if.nature |
1 | yes |
sub |
statement.sub |
— | yes |
templating_transform |
service.templating.transform |
2 | yes |
topic_add_owner |
service.topic.add_owner |
— | yes |
topic_assign_sla_config |
service.topic.assign_sla_config |
— | yes |
topic_calculate_effort |
service.topic.calculate_effort |
6 | yes |
topic_delete |
service.topic.delete |
— | yes |
topic_get_with_condition |
service.topic.get_with_condition |
1 | yes |
topic_inactivity_daemon |
service.topic.inactivity_daemon |
— | yes |
topic_load |
service.topic.load |
— | yes |
topic_related |
service.topic.related |
8 | yes |
topic_remove_file |
service.topic.remove_file |
3 | yes |
topic_remove_owner |
service.topic.remove_owner |
— | yes |
topic_status |
service.topic.status |
— | yes |
topic_upload |
service.topic.upload |
— | yes |
trackedasset_add |
service.trackedasset.add |
— | yes |
trackedasset_verify |
service.trackedasset.verify |
— | yes |
try |
statement.try |
— | yes |
try_with_catch |
statement.try_with_catch |
— | yes |
user_group_manage_roles |
service.user_group.manage_roles |
1 | yes |
user_load |
service.user.load |
1 | yes |
user_manage_groups |
service.user.manage_groups |
1 | yes |
user_manage_roles |
service.user.manage_roles |
1 | yes |
validate_stash_variables |
service.validate.stash_variables |
— | yes |
var_expect |
statement.var.expect |
— | yes |
var_push |
statement.var.push |
2 | yes |
var_set_jsexpr |
statement.var.set_jsexpr |
2 | yes |
var_set_to_ci |
statement.var.set_to_ci |
— | yes |
vault_get_credential |
service.vault.get_credential |
— | yes |
vault_set_credential |
service.vault.set_credential |
— | yes |
workflow_if_project |
statement.workflow.if_project |
— | yes |
workflow_if_role |
statement.workflow.if_role |
— | yes |
workflow_if_status_from |
statement.workflow.if_status_from |
1 | yes |
workflow_transition |
service.workflow.transition |
3 | yes |
workflow_transition_match |
service.workflow.transition_match |
4 | yes |
Import behaviour¶
A rule that has not changed plans as UNCHANGED: its version does not move and
no version row is written.
A changed rule goes through the same save the Rule Designer uses. The steps are
compiled before anything is stored, so a rule that does not build is refused
rather than written, and the change is versioned exactly as an edit in the
browser would be. opids are regenerated on the way in.
A step naming an operation this installation does not have, or pointing at an object that is not there, is reported with its file and line and stops the import.
--prune scopes rules by type, so a file holding only pipelines can never
propose deleting a workflow.
Rules in the UI¶
The Rule Designer has an HCL view over the same converter, and the rule list can open a rule as HCL directly. See In the UI.