I am trying to call the variable like this:
with:
tags: ${{ inputs.push_tag_to_release && 'op/post:'[env.tag] || 'op/post:${{ env.tag }}' }}
where,
env.tag = 0.13 (value)
but both the ways [env.tag] or ${{ env.tag }} are showing as incorrect/not-supported.
I tried like this,
tags: ${{ inputs.push_tag_to_release && 'op/post:'[env.tag] || 'op/post:${{ env.tag }}' }}
and the format function as well:
tags: ${{ inputs.push_tag_to_release && 'op/post:format({0},env.tag)' || 'op/post:${{ env.tag }}' }}
but not working in any way.
Related
I have some model YAML:
version: 2
models:
- name: my_model
columns:
- name: foo
description: My bestest column
...If I make other models which inherit from this one, is there any way to refer back to this column definition when documentation is generated, or do I need to copy-paste the column definition for each model in which the column appears?
In other words, is there a way of defining a column only once to make edits and updates easier.
Cheers,
Graham
I think there are two ways to do it.
1. using macro
create a file that contains all those reusable descriptions. you could even use params to customize the description.
e.g. doc_library.sql
{% macro column_bestest_doc(col_name) %}
My bestest column {{ col_name }}
{% endmacro %}
then use it in dbt_project.yml
version: 2
models:
- name: my_model
columns:
- name: foo_1
description: {{column_bestest_doc(foo_1)}}
- name: my_model_another
columns:
- name: foo_2
description: {{column_bestest_doc(foo_2)}}
2. using YAML anchor
you could do YAML anchors in dbt_project.yml as in any other yml files.
version: 2
models:
- name: my_model
columns:
- name: &foo
description: My bestest column
- name: my_model_another
columns:
- name: *foo
ref:
https://support.atlassian.com/bitbucket-cloud/docs/yaml-anchors/
https://medium.com/#kinghuang/docker-compose-anchors-aliases-extensions-a1e4105d70bd
We have been thinking about this problem extensively as well... our current solution is to modify the generate_model_yaml macro:
{% macro generate_model_yaml(model_name) %}
{% set model_yaml=[] %}
{% set existing_descriptions = fetch_existing_descriptions(model_name) %}
-- # TO DO: pass model to fetch()
-- if column not blank on current model, use description in returned dict
-- otherwise, use global
-- also extract tests on column anywhere in global scope
{% do model_yaml.append('version: 2') %}
{% do model_yaml.append('') %}
{% do model_yaml.append('models:') %}
{% do model_yaml.append(' - name: ' ~ model_name | lower) %}
{% do model_yaml.append(' description: ""') %}
{% do model_yaml.append(' columns:') %}
{% set relation=ref(model_name) %}
{%- set columns = adapter.get_columns_in_relation(relation) -%}
{% for column in columns %}
{%- set column = column.name | lower -%}
{%- set col_description = existing_descriptions.get(column, '') %}
{% do model_yaml.append(' - name: ' ~ column ) %}
{% do model_yaml.append(' description: "' ~ col_description ~ '"') %}
{% do model_yaml.append('') %}
{% endfor %}
{% if execute %}
{% set joined = model_yaml | join ('\n') %}
{{ log(joined, info=True) }}
{% do return(joined) %}
{% endif %}
{% endmacro %}
And then get the first description found that matches the column, with fetch_existing_descriptions():
{% macro fetch_existing_descriptions(current_model) %}
{% set description_dict = {} %}
{% set current_model_dict = {} %}
{% for node in graph.nodes.values() | selectattr("resource_type", "equalto", "model") %}
{% for col_dict in node.columns.values() %}
{% if node.name == current_model %}
-- Add current model description to seperate dict to overwrite with later
{% set col_description = {col_dict.name: col_dict.description} %}
{% do current_model_dict.update(col_description) %}
{% elif description_dict.get(col_dict.name, '') == '' %}
{% set col_description = {col_dict.name: col_dict.description} %}
{% do description_dict.update(col_description) %}
{% endif %}
{% endfor %}
{% endfor %}
-- Overwrite description_dict with current descriptions
{% do description_dict.update(current_model_dict) %}
{% if var('DEBUG', False) %}
{{ log(tojson(description_dict), info=True) }}
{% else %}
{{ return(description_dict) }}
{% endif %}
{% endmacro %}
Finally, we use a bash script with the path to the model to write/overwrite a yaml file using the modified generate_model_yaml above:
#!/bin/bash
# Generates documentation for dbt models.
# Usage:
# Run from within the gold folder.
# Run with no args for all models. Provide optional relative model path to generate docs for just one model:
# Eg. `$ bash ./scripts/generate_docs.sh [./models/path/to_your_model.sql]`
if [[ -n $1 ]]; then # Build array of one model if optional arg provided
yml="${1%.sql}.yml" # Create model yml filename
touch "$yml" && rm "$yml" || exit 1 # Ensure filepath works by testing creation
array=("$yml")
else # Create array of yml
array=()
while IFS= read -r -d $'\0'; do
if [[ ${REPLY} != *"src"* ]]; then # Only proceed for model yml files (don't contain "src")
if [[ -n $1 ]]; then
# Include only the model yml of the optional arg
if [[ $(basename $yml) == $(basename $REPLY) ]]; then
array+=("$REPLY")
fi
else
array+=("$REPLY")
fi
fi
done < <(find "./models/" -name "*.yml" -print0)
fi
# Create copy model yml with prescribed yml containing docs standard.
for i in "${array[#]}"
do
model=$(basename $i | sed -E 's|[.]yml||g')
generated_yml=$(dbt run-operation generate_model_yaml --args "model_name: $model" | sed '1d')
echo "$generated_yml" > "${i}_copy" # Create non-yml copy file to allow script to complete
done
# Once all copies are created, replace originals
for i in "${array[#]}"
do
cat "${i}_copy" > $i
rm "${i}_copy"
done
I am using helmfile for my helm releases.
I have a yaml file projects.yaml
# projects.yaml
- yako
- pera
- okta
In values.yaml.gotmpl, i want to iterate thru the content of projects.yaml :
# values.yaml.gotmpl
{{ $projects := readFile 'projects.yaml' }}
{{ range $_, $project := $projects }}
# do something with $project . e.g: tpl (readFile 'proj-config.yaml') (dict $name $project)
{{ end}}
Unfortunately , i got this error :
failed to render [values.yaml.gotmpl], because of template: stringTemplate:60:41:
executing "stringTemplate" at <$projects>: range can't iterate over projects:
- yako
- pera
- okta
I made a lot of blind attempts to make it work :
{{ range $_, $project := $projects | fromYaml }}
{{ range $_, $project := $projects | toYaml }}
{{ range $_, $project := $projects | list }}
No way 😩
{{ $projects := readFile "./projects.yaml"}}
{{ range $_, $project := get "projects" $projects }}
{{ $project.attr1 }}
{{end}}
I have the following slim template:
.dc-credit-card-label 'v-bind:class' => "{MyClass}"
span.dc-credit-card--stars ••••
span.dc-credit-card--stars ••••
span.dc-credit-card--stars ••••
span
| {{ payment.last4 }}
So I am trying to set the MyClass = 'some-cool-class'
but this doesn't work
Is there any chance to do this?
A comment from this git issue:
You just use the directive tags like normal but make them slim syntax.
.signed-in v-if="user"
= "Wecome, {{ user.name }}"
a.sign-out-button v-on:click="signOut" Sign out
So, use it "normal":
.dc-credit-card-label :class="{MyClass}"
span.dc-credit-card--stars ••••
span.dc-credit-card--stars ••••
span.dc-credit-card--stars ••••
span
| {{ payment.last4 }}
Is there a way to use for loops in YAML templates for Jenkins Job Builder?
Like it Ansible with jinja2
Something like
jobs: job1, job2, job3
- trigger-builds:
- project:
{% for j in jobs %}
project_{{ j }}
{% endfor %}
So it will be like
- trigger-builds:
- project: project_job1 project_job2 project_job3
From Documentation: https://docs.openstack.org/infra/jenkins-job-builder/definition.html
- project:
name: project-name
axe1:
- axe1val1
- axe1val2
axe2:
- axe2val1
- axe2val2
axe3:
- axe3val1
- axe3val2
exclude:
- axe1: axe1val1
axe2: axe2val1
axe3: axe3val2
- axe2: axe2val2
axe3: axe3val1
jobs:
- build-{axe1}-{axe2}-{axe3}
- job-template:
name: build-{axe1}-{axe2}-{axe3}
builders:
- shell: "echo Combination {axe1}:{axe2}:{axe3}"
The above example will omit the jobs:
build-axe1val1-axe2val1-axe3val2
build-axe1val1-axe2val2-axe3val1
build-axe1val2-axe2val2-axe3val1
You can use jinja2 template for achieving this purpose.
Something like this:
- builder:
name: test-builder
builders:
- shell:
!j2: |
{{ var }}
{% for item in test_list -%}
{{ item }}
{% endfor %}
- job:
name: test-job
builders:
- test-builder:
var: "test variable"
test_list:
- a
- b
- c
Question
How do I do something like this:
{{ $use_ssl := (ne $.Env.CERT_NAME "") }}
where $.Env.CERT_NAME may be nil/undefined. If it is nil, it gives this error:
at <ne $.Env.CERT_NAME "">: error calling ne: invalid type for comparison
Note: I have no control over the objects passed in to the Go template so have to solve this entirely within the template itself.
What I've tried
I tried to work around by first checking to see if it is non-empty:
{{ $use_ssl := ( ($.Env.CERT_NAME) && (ne $.Env.CERT_NAME "") ) }}
but it gives this error:
unexpected "&" in operand
So I switched to this, which is allowed syntactically:
{{ $use_ssl := (and ($.Env.CERT_NAME) (ne $.Env.CERT_NAME "") ) }}
but then I lose the short-circuit evaluation that I would get with the && operator and I'm back to getting this error again:
at <ne $.Env.CERT_NAME ...>: error calling ne: invalid type for comparison
Okay, I thought, if I can't do it in a nice one-liner, and Go doesn't have a ternary operator, that's fine, I'll just do it the idiomatic Go way, which is apparently if/else.
{{ if $.Env.CERT_NAME }}
{{ $use_ssl := (ne $.Env.CERT_NAME "") }}
{{ else }}
{{ $use_ssl := false }}
{{ end }}
But then of course I run into scoping issues, because if inexplicably (or at least annoyingly) creates a new variable scope (unlike in Ruby/ERB templates that I am more used to), so apparently I can't even do this:
{{ if $.Env.CERT_NAME }}
{{ $use_ssl := true }}
{{ else }}
{{ $use_ssl := false }}
{{ end }}
# $use_ssl: {{ $use_ssl }}
without getting this error now:
undefined variable "$use_ssl"
"No sweat", I thought. I'll just declare the variable in the outside scope so it will have the correct scope and the inner scope will still be able to change that variable (the one with the outer scope). (That's how it works in Ruby, by the way.)
Nope, apparently all that does is create 2 different variables with the same name but different scopes (how's that for confusing!):
{{ $use_ssl := false }}
{{ if $.Env.CERT_NAME }}
{{ $use_ssl := true }}
# $use_ssl: {{ $use_ssl }}
{{ else }}
{{ $use_ssl := false }}
{{ end }}
# $use_ssl: {{ $use_ssl }}
# $use_ssl: true
# $use_ssl: false
I've also tried inlining the if statement like this:
{{ $use_ssl := if $.Env.CERT_NAME { true } }}
but that gives this error:
unexpected <if> in command
Apparently if statements can't be used as expressions in Go like they can in Ruby?
I also get syntax errors if I try the various alternatives to the ternary operator suggested in What is the idiomatic Go equivalent of C's ternary operator?, like:
c := map[bool]int{true: 1, false: 0} [5 > 4]
And sure, you can read variables from outer scopes in inner scopes with $.something but how do you set $.something in the inner scope?
If not like that, then how??
So what have I missed? Is this even possible in a Go template?
Go templates (I'm new to them) seem very limiting. Almost everything you can do in Go itself is not possible in a template. But hopefully there is a workaround...
http://play.golang.org/p/SufZdsx-1v has a clever workaround involving creating a new object with {{$hasFemale := cell false}} and then setting a value with $hasFemale.Set true, but how can I do something like that without having access to the code that evaluates the template (where they are calling template.FuncMap)?
Others who have tried and failed
https://groups.google.com/forum/#!topic/golang-nuts/MUzNZ9dbHrg
This is the biggest (and only) problem I have with Go. I simply do not understand why this functionality has not been implemented yet.
When the template package is used in a generic context (eg. Executing
an arbitrary template file with an arbitrary json file), you might not
have the luxury of doing precalculations.
https://github.com/golang/go/issues/10608
This is probably as designed, but it would be really nice if there was a way to get the changed $v outside of the conditional.
This is the #1 template question we get over at Hugo (https://github.com/spf13/hugo). We have added a hack [$.Scratch.Set "v1" 123] to work around it for now ...
Currently working solution
If you update the scope rather than declare a variable, either by using set or by using merge you will be able to access it outside of the if clause.
{{- if eq .podKind "core" -}}
{{- $dummy := set . "matchNodePurpose" .Values.scheduling.corePods.nodeAffinity.matchNodePurpose }}
{{- else if eq .podKind "user" -}}
{{- $dummy := set . "matchNodePurpose" .Values.scheduling.userPods.nodeAffinity.matchNodePurpose }}
{{- end -}}
# Will now output what you decided within an if/else if clause
{{- .matchNodePurpose }}
Future solution (Available with Helm 2.10)
I came across the same question in the context of Helm templates which are go templates with some additional features pre-installed such as Sprig.
28 March 2018, in this pr a Terenary operator was added to Sprig, and in time Helm will have them as well solving the issue both you and I have.
terenary
true | ternary "b" "c" will return "b"
false | ternary "b" "c" will return "c"
Your fourth try would work if you'd use the assignment operator instead of the definition operator:
{{ $use_ssl := false }}
{{ if $.Env.CERT_NAME }}
{{ $use_ssl = true }} # notice the missing colon!
{{ else }}
{{ $use_ssl = false }}
{{ end }}
I think I may have found a workaround for my particular problem, though I would love to hear other answers that solve the problem more generally.
Came across this line in https://github.com/jwilder/nginx-proxy/blob/1e0b930/nginx.tmpl#L91:
{{ $default_host := or ($.Env.DEFAULT_HOST) "" }}
which gave me another idea to try. I guess the solution is to use a combination of or and set extra temporary variables...
{{ $cert_name := or $.Env.CERT_NAME "" }}
{{ $use_ssl := ne $cert_name "" }}