Code Monkey home page Code Monkey logo

octostache's Introduction

Octostache is the variable substitution syntax for Octopus Deploy.

Octopus allows you to define variables, which can then be referenced from deployment steps and in scripts using the following syntax:

#{MyVariable}

This library contains the code for parsing and evaluating these variable expressions.

Usage is simple: install Octostache from NuGet.org, then create a VariableDictionary:

var variables = new VariableDictionary();
variables.Set("Server", "Web01");
variables.Set("Port", "10933");
variables.Set("Url", "http://#{Server | ToLower}:#{Port}");

var url = variables.Get("Url");               // http://web01:10933
var raw = variables.GetRaw("Url");            // http://#{Server | ToLower}:#{Port}
var eval = variables.Evaluate("#{Url}/foo");  // http://web01:10933/foo

More examples can be found in UsageFixture.

Contributing

๐Ÿ™ We welcome Pull Requests โค๏ธ๐Ÿง‘โ€๐Ÿ’ป

Code Cleanup

The first stage of our CI/CD pipeline for Octostache runs a ReSharper code cleanup, to keep everything neat and tidy.

Your PR won't be able to pass without ensuring the code is clean. You can do this locally via the ReSharper CLI tools, which is how we enforce it during our builds.

All the formatting settings are committed to Octostache.sln.DotSettings, so as long as you don't override these with an Octostache.sln.DotSettings.User file, you should be all good.

To get started with code cleanup the easiest way (via dotnet tool), get the CodeCleanup tool installed globally (one-time):

dotnet tool install -g JetBrains.ReSharper.GlobalTools

then execute the cleanup:

jb cleanupcode ./source/Octostache.sln

We don't try to enforce this through build scripts or pre-commit hooks, it's up to you to run when you need to. If you use the Rider IDE, it seems to apply another opinion or two when running the code cleanup, and might get different results to the CLI approach; we don't recommend cleaning up this way.

octostache's People

Contributors

andrew-at-octopus avatar andrew-moore-octo avatar chrischu avatar corey-underdown avatar damovisa avatar dkarzon avatar droyad avatar egorpavlikhin avatar espenrl avatar flamage82 avatar hnrkndrssn avatar isaaccalligeros95 avatar markryd avatar matt-richardson avatar mcasperson avatar michaeljcompton avatar michaelnoonan avatar mik-ky avatar mjhilton avatar mjrichardson avatar n-lson avatar paulstovell avatar pondidum avatar rain-on avatar rhysparry avatar simoncropp avatar slewis74 avatar uglybugger avatar veochen-octopus avatar zentron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

octostache's Issues

Missing JSON property evaluates to "null" string rather than undefined.

When evaluating a json object in a Octostache template and the json object doesn't have a property defined - the #{if item.MissingProperty} is not evaluated correctly since the value of item.MissingProperty is "null". I think it should evaluate to falsy value - like undefined.

See reproduction using Octostache 2.3.1 nuget package:

var variables = new VariableDictionary();
variables.Set("test", @"
[
      #{each item in Collection}
      {
        ""Name"": ""#{item.Name}"",
        ""ExistingProperty"": #{item.ExistingProperty},
        ""MissingArrayPropertyWithStringNulllCheck"": #{if item.MissingArrayProperty != ""null""}#{item.MissingArrayProperty}#{else}[]#{/if},
        ""MissingArrayPropertyWithFalsyCheck"": #{if item.MissingArrayProperty}#{item.MissingArrayProperty}#{else}[]#{/if},
        ""MissingArrayProperty"": #{item.MissingArrayProperty},
        ""MissingStringPropertyWithStringNulllCheck"": #{if item.MissingStringProperty != ""null""}#{item.MissingStringProperty}#{else}""""#{/if},
        ""MissingStringPropertyWithFalsyCheck"": #{if item.MissingStringProperty}#{item.MissingStringProperty}#{else}[]#{/if},
        ""MissingStringProperty"": #{item.MissingStringProperty}

      #{if Octopus.Template.Each.Last == ""True""}
        }
      #{/if}
      #{if Octopus.Template.Each.Last == ""False""}
      },
      #{/if}
      #{/each}
]");

variables.Set("Collection[0]", @"
{
  ""Name"": ""Name1"",
  ""ExistingProperty"": ""Value1""
}");

variables.Set("Collection[1]", @"
{
  ""Name"": ""Name2"",
  ""ExistingProperty"": ""Value2"",
  ""MissingArrayProperty"": [""A"", ""B""],
  ""MissingStringProperty"": ""StringValue""
}");


Console.WriteLine(variables.Get("test"));

Custom resolvers

Don't suppose anyone knows if there is a way to use custom resolvers??

It would be awesome if you could pump unresolved things through a Func<string, string> then I could nip off to key vault etc to get the value.

Cheers

Test Issue

This is a test issue for validating that our Release Notes generation works correctly

JsonEscape variable substitution filter doesn't escape some characters properly.

Using the JsonEscape filter in extended variable syntax doesn't have the expected result.

We'd expect an input like

{
    "key": "#{MyCert.CertificatePem | JsonEscape}"
}

to be expanded to

{
    "key": "-----BEGIN CERTIFICATE-----\r\nMIIC7DCCAdSgAwIBAgIQZryBaAe+ebJFmD/KMi4w0zANBgkqhkiG9w0BAQsFADAU\r\nMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcxMjA0MDI0NzM3WhcNMjIxMjA0MDAw\r\nMDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB...

Instead we get:

{
    "key": "-----BEGIN CERTIFICATE-----\
\
MIIC7DCCAdSgAwIBAgIQZryBaAe+ebJFmD/KMi4w0zANBgkqhkiG9w0BAQsFADAU\
\
MRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTcxMjA0MDI0NzM3WhcNMjIxMjA0MDAw\
\
MDAwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB...

Conditionals in JSON with escaped strings not parsed correctly.

see also OctopusDeploy/Issues#3213

Variables with JSON values that contain embedded conditionals with escaped quotes aren't parsed.

In the referenced issue that comes with IIS bindings

"Octopus.Action.IISWebSite.Bindings": "[{\"protocol\":\"http\",\"ipAddress\":\"*\",\"port\":\"80\",\"host\":\"\",\"thumbprint\":null,\"certificateVariable\":null,\"requireSni\":false,\"enabled\":\"#{if Octopus.Action.TargetRoles == \\\"Some Role\\\"}True#{/if}\"}, ...]",

Note: it's possible to get round this by assigning the string to a variable and using variable-variable comparison.

ParseTemplateAndGetArgumentNames is broken

Many years ago, I asked for ParseTemplateAndGetArgumentNames and my wish was granted. However somewhere along the way it got broken.

Steps to reproduce:

	 foreach( var a in TemplateParser.ParseTemplateAndGetArgumentNames("#{a.b.c}"))
	 {
	 	Console.WriteLine(a);
	 }

What I'm expecting to see:

a.b.c

What I'm actually seeing:

a
b
c

The templating engine still correctly treats a.b.c as a single var, but ParseTemplateAndGetArgumentNames regressed somewhere and returns wrong result.

License?

Hi, I'm interested in embedding this in a tool, however there is no obvious license for it.

No way to access key when iterating over certificate variables (and probably also other complex variables)

In the documentation (https://octopus.com/docs/projects/variables/variable-substitutions#VariableSubstitutionSyntax-Iteratingoversetsofvalues) it is stated that I can access the key of an iteration by just using the iteration variable,
e.g. for

#{each variable in Variables}
Key=#{variable} 
#{/each}

with variables like this:

Variables[a] = 5
Variables[b] = 7

the output is

Key=a
Key=b

However, when iterating through complex variables (e.g. certificates) there seemingly is no way to access the key, .e.g.
when using the same code but with the following variables:

Variables[a] = (Certificate with ID Certificate-1)
Variables[b] = (Certificate with ID Certificate-2)

the output is

Key=Certificate-1
Key=Certificate-2

Is there any way to access the key ("a"/"b" in this example) when iterating over complex variables?

Expected behaviour for template containing text like #{$Foo}?

I encountered an issue when transforming a file in Octopus Deploy where a piece of text in the file in the format of #{$Foo} caused the error:

Parsing failure: unexpected '#'; expected end of input (Line 1, Column 1); recently consumed:

I am not trying to substitute this piece of text it just happens to be in file being transformed. I've added a test case as an example:

https://github.com/jasonmitchell/Octostache/commit/018e6c609cc5f4f5e082215b4039d15a448faf74

The error message for this test is the same as the other cases for the test. I wanted to clarify if this is expected behaviour or is a bug in the template parser?

If this is expected is there anyway to work around other than removing the piece of text from the file?

Feature Request: ElseIf

Hey Octo Crew, would adding an elseif be possible?

Below is an example from Variable Substitutions.

#{if Octopus.Environment.Name == "Development"}
  Do this if it's Development
#{else}
  #{if Octopus.Environment.Name == "Test"}
    Do this if it's Test
  #{else}
    Do this if it's neither
  #{/if}
#{/if}

If I understand it right, every extra if has to be nested and would quickly get out of control. It would be nice to express complex checks as.

#{if Octopus.Environment.Name == "Development"}
  Do this if it's Development
#{elseif Octopus.Environment.Name == "Test"}
  Do this if it's Test
#{else}
  Do this if it's neither
#{/if}

Probably not wise to add too many conditions but what's missing from the examples when it comes to run conditions is one level of #{if Octopus.Deployment.Error == "True"}False{/if} because you can't use "Variable Conditions" without disabling "Success: only run when previous steps succeed"

TemplateParser.ParseTemplate() crashes if the template contains a reference to a variable with "special" characters in name

A call to TemplateParser.ParseTemplate(foo) throws an exception on some valid input such as #{foo!}:

Parsing failure: unexpected '#'; expected end of input (Line 1, Column 1); recently consumed: 
at Sprache.ParserExtensions.Parse[T](Parser`1 parser, String input)
at Octostache.Templates.TemplateParser.ParseTemplate(String template)
at IHS.Castle.Tools.OctopusUtilities.WebApi.Program.Main(String[] args) in S:\Connect.BuildTools.TestAndSources\src\IHS.Castle.Tools.OctopusUtilities.WebApi\Program.cs:line 14

Octopus Deploy allows to create variables with all kinds of characters in the name, even crazy ones like !@#$%^&*()_+-={}[]:";'<>?,./ (yes, I was able to create a variable called just that for a test), which while not the greatest practice, should be supported by this library. My team had one legitimate case where one of those characters was used, but this crashed TemplateParser.

Looking at the code of TemplateParser, it only allows the following non-alphanumerical, non-whitespace characters: _-:/~().

I could create a PR to change this, but I can't find any documentation on what characters are actually supported by Octopus Deploy in variable names.

Truncate

I'd like to enforce a maximum length on my variables with "octostashe", what do you recommend? Truncate would be great if it didn't add an ellipsis and just, you know, truncated.

Allow variables to be saved to other formats/persistence stores

Hi,

It would be nice if Octostache allowed variables to be persisted in other formats than json and to other stores other than just a regular file.

To my mind this would mean extracting the serialization and formatting logic out of variable dictionary, behind an interface.

I am happy to work on this if this would be something that would be useful.
Cheers
sean.

Support converting to Base64

Please support converting the string value to base64.

#{Bar | ToBase64}

Where where, when Bar= Baz the outcome would be: QmF6

Allow filter functions in #{if}

Atm this is not supported by #{if}/#{unless}. The current workaround is to extract "temporary variables", but this is a) cumbersome and b) doesn't work "inline" in transformation config files.

Example use cases:

  • #{if My.Var | Trim != ""}oh it's empty or whitespace#{/if}
  • #{if My.Var | Contains meow}oh it seems to contain a cat#{/if}
  • #{if My.Url | UriPart Scheme == "https"}oh it's https#{/if}

As this conflicts with the (arbitrarily long) function argument list syntax, maybe it's better to use a "sub expression syntax", something like:
#{if #{SomeUrl | Trim} != ""}oh it's empty or whitespace#{/if}

Iterating over Octopus.Action returns instances in the improper order

Using a sample email template from here: https://octopus.com/docs/deployment-process/steps/email-notifications, the iterator over Octopus.Action collection
#{each action in Octopus.Action} .... #{/each}
consistently lists the last step as first.
In OD process, the steps are:

  1. Deploy Process
  2. Start service
  3. Send Email notification using the template.

The email arrives consistently listing the actions in the following order:

  1. Send Email notification using the template.
  2. Deploy Process
  3. Start service

Using Octopus v2018.8.4

Possibility to support sorting for collections

Hi

I am wondering if there exists a possibility to affect the sorting of collection, e.g. when traversing Releases for Deployment changes template as described here https://octopus.com/docs/releases/deployment-notes#templates

e.g.

#{each release in Octopus.Deployment.Changes sort desc}

Reason, in many other release notes, the notes are sorted in a descending order, so that latest release is on top. Would be nice to be able to have this in OctopusDeply as well.

Best regards
Lars Jakobsen

Filters like PeriodsToHypens, HypensToUnderscores etc

Our environment names are things like dev.mysite.com and it would be helpful to be able to insert a cleaned up version of these these into other variables without the special characters e.g. so that they can be used in a database name.

It would be great to have a few filters like PeriodsToHypens, HypensToUnderscores, UnderscoresToPeriods etc. which could be used to make the variables safe.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.