github gruntwork-io/terragrunt v1.2.2

one hour ago

๐ŸŽ๏ธ Performance Improvements

Faster dependency discovery in large repositories

run --all, and find or list with --dependencies, are faster in large repositories, including ones with no dependency blocks. The time spent linking units to their dependencies now grows linearly with the number of units instead of quadratically.

In benchmarks on an AMD Ryzen AI Max+ 395, discovering units and their dependencies in a generated repository of 10-unit dependency chains:

units before after
10 0.63ms 0.63ms
100 5.2ms 5.0ms
1,000 56ms 47ms
10,000 1.32s 443ms

At 10,000 units, memory allocated during discovery dropped from 8.6 GB to 1.9 GB.

Faster discovery with dependent filters

Terragrunt wastes less time resolving symlinks in discovery. Dependent filters, such as --filter '...vpc' were able to reduce the number of wasted syscalls to resolve symlinks, improving dependent discovery.

On a repository of 1,024 units, discovery with a dependent filter took 30% less time from the repository root and 47% less time from the target unit's directory on an M3 Max. It also allocated 12-16% less memory.

Faster discovery of dependencies

Discovery prepared to read a terragrunt.stack.hcl in every directory named by a dependency or dependencies block, even when the directory was a unit. It now does that work only when the stack file exists.

In benchmarks on an AMD Ryzen AI Max+ 395, selecting the dependents of a unit that every other unit depends on, run from that unit's directory:

units before after
10 2.9ms 2.3ms
100 118ms 86ms
1,000 11.1s 8.0s

At 1,000 units, memory allocated during discovery dropped from 26.7 GiB to 10.3 GiB.

๐Ÿ’ก Tips Added

inputs-read-not-tracked โ€” Points at files read in inputs that reading filters miss

Terragrunt does not track a file read in inputs. A unit with this configuration is not selected by --filter 'reading=config.yml' or by a Git filter when config.yml changes:

# terragrunt.hcl

inputs = {
  message = yamldecode(file("config.yml")).message
}

The same applies to inputs in an autoinclude block of a stack file.

Commands that track reads, such as run --all with a reading or Git filter and find --reading, now print the inputs-read-not-tracked tip pointing at each such read:

TIP (inputs-read-not-tracked): Terragrunt does not track files read in `inputs`, so reading and Git filters miss the units and stacks that read them.

Untracked file read in `inputs`
 --> app/terragrunt.hcl:4:24
  |
4 |   message = yamldecode(file("config.yml")).message
  |                        ^^^^^^^^^^^^^^^^^^ Read the file in `locals` and reference the local here.

Untracked file read in an `autoinclude` block's `inputs`
 --> live/terragrunt.stack.hcl:16:29
   |
16 |       policy = templatefile("policy.json.tftpl", { role_arn = dependency.iam.outputs.role_arn })
   |                             ^^^^^^^^^^^^^^^^^^^
   |
   = Mark the template as read with `mark_as_read` in the stack's `locals`, then pass the local as the path here.

See https://docs.terragrunt.com/features/filter/attributes#reading-based-expressions

See Reading-Based Expressions. Suppress the tip with --no-tip inputs-read-not-tracked or --no-tips.

๐Ÿ”’ Strict Controls Added

cas-source-inside-stack strict control

A unit or stack block with update_source_with_cas could set a source inside the directory of its own stack file, e.g. a catalog with its stack at the root and its units under units/:

# catalog/terragrunt.stack.hcl

unit "foo" {
  source                 = "./units/foo"
  update_source_with_cas = true
  path                   = "foo"
}

Stack generation copies the stack directory whole. For a stack "bar" block with source = "../catalog", the generated stack contained the unit twice, and run --all ran both, the copy without the values its stack gives the generated unit:

.terragrunt-stack/bar/.terragrunt-stack/foo
.terragrunt-stack/bar/units/foo

Existing support will be retained for v1.x for backwards compatibility, to obey the Terragrunt 1.0 guarantees.

Terragrunt now warns about each such block:

WARN  Setting the source of a `unit` or `stack` block with `update_source_with_cas` to a directory inside the stack directory is deprecated and will be removed in a future version of Terragrunt. Stack generation copies the stack directory whole, so `run --all` also runs the copy. Move the source out of the stack directory, and select the stack with a `//` subdirectory in its source.
WARN  stack bar: unit "foo" in terragrunt.stack.hcl sets update_source_with_cas on source "./units/foo" inside the stack directory, so the generated stack also contains a copy of it; move the source out of the stack directory and select the stack with a // subdirectory in its source

With the new cas-source-inside-stack strict control enabled, each of those blocks is an error instead:

terragrunt stack generate --strict-control cas-source-inside-stack

Move the stack into a subdirectory of the catalog, e.g. stacks/bar, keep its sources outside that subdirectory, and select it with source = "../catalog//stacks/bar". The cas-source-inside-stack control is also part of the deprecated-configs group.

๐Ÿงช Experiments Added

no-dot-terragrunt-cache experiment adds a terraform.no_dot_terragrunt_cache attribute

Enable the no-dot-terragrunt-cache experiment and set no_dot_terragrunt_cache = true in the terraform block of a unit without a source. Terragrunt then runs OpenTofu/Terraform in the unit directory instead of a copy in .terragrunt-cache, so local module paths resolve as written. The attribute is merged through include.

terraform {
  no_dot_terragrunt_cache = true
}
terragrunt run --experiment no-dot-terragrunt-cache -- plan

Setting it to true together with a source, or without the experiment enabled, returns an error.

variables-block experiment adds a variables block

Enable the variables-block experiment to set OpenTofu/Terraform variables with a variables block. Its kind attribute chooses how Terragrunt passes the inputs: TF_VAR_ environment variables (env, the default), a terragrunt.auto.tfvars file (tfvar), or a terragrunt.auto.tfvars.json file (json). Writing inputs to a file avoids the operating system's limit on the size of a process environment, which a unit with many or large inputs can exceed.

variables {
  kind     = "tfvar"
  validate = true

  inputs = {
    vpc_id = dependency.vpc.outputs.vpc_id
  }
}
terragrunt run --experiment variables-block -- plan

With the experiment enabled, terragrunt.auto.tfvars and terragrunt.auto.tfvars.json are reserved names in .terragrunt-cache. Terragrunt removes a file with either name from the cache when the unit has no inputs of that kind, so rename any such file in a unit, module, or generate block.

๐Ÿงช Experiments Updated

mcp-command โ€” terragrunt mcp serves a catalog tool

The mcp command serves a new catalog tool. It returns the components terragrunt catalog returns, each in the shape terragrunt catalog --format=jsonl prints. Its component_source is the value a terraform block's source takes.

limit caps how many components come back, and include_docs adds each component's README. A repository that fails to load is listed in failures, and the components of the others still come back. Cloning a remote repository runs git, which needs --allow=exec. A local directory needs no capability.

mcp-command โ€” --allow=docs relays the Terragrunt docs MCP server

An agent connected to terragrunt mcp could not read the Terragrunt documentation unless the Terragrunt docs MCP server was configured as a second server. --allow=docs now relays that server's tools and resources through terragrunt mcp, each tool under a docs_ prefix, e.g. search_docs is served as docs_search_docs:

// .mcp.json

{
  "mcpServers": {
    "terragrunt": {
      "command": "terragrunt",
      "args": ["mcp", "--allow=docs"],
      "env": {
        "TG_EXPERIMENT": "mcp-command"
      }
    }
  }
}

Like every other capability, docs is denied unless granted, and granting http does not grant it. Every argument an agent passes to a docs_ tool leaves the machine, including any configuration it pastes in. If the docs server does not answer when the server starts, the server starts without the docs_ tools and logs a warning, and only a restart tries again.

See the mcp command docs for details.

mcp-command โ€” A fmt tool formats HCL files

The mcp server now serves a fmt tool, which rewrites the .hcl files under a directory into canonical format, as hcl fmt does. check reports the files that need formatting without changing any, diff adds a unified diff for each, file formats a single file, and filter narrows the set by path.

A server started with no --allow flag still lets an agent rewrite the .hcl files under its root. Symlinks are skipped, and a file outside the root is refused.

mcp-command โ€” terragrunt mcp serves a scaffold tool

The mcp command serves a new scaffold tool. It writes new configuration from a module, unit, or stack source as terragrunt scaffold does, without prompting. values sets what to fill in. A required value left out is written as a TODO placeholder and listed in todo.

Files go in output_folder, which defaults to working_dir, must resolve under the server root, and must be empty or not exist yet. A failed call removes what it wrote. A remote source needs --allow=http, or --allow=exec for git. A local source needs no capability.

A template's shell helpers and hooks never run, even under --allow=exec. The tool refuses a template that declares dependencies or uses template syntax in a file or directory name, and a source with a symlink leading out of it.

otel-logs - More reliable log export

The otel-logs experiment exports Terragrunt's logs as OpenTelemetry log records. This release makes the export more reliable:

  • Records logged outside a unit, such as by the run queue or the OpenTofu/Terraform output of a single-unit run, now link to the root command span instead of carrying no trace ID.
  • Buffered records are flushed when a run is interrupted, and the flush waits at most 30 seconds.
  • A slow or failed trace or metric flush no longer drops buffered log records.
  • Record bodies no longer include ANSI color codes.

See OpenTelemetry for the settings and a Docker Compose example that sends traces to an OpenTelemetry collector and logs to Quickwit.

slow-task-reporting - One progress line on terminals, log lines in CI

Slow operations share one progress line, cut to the terminal width. Log lines print above it:

| Downloading source from git::https://github.com/acme/modules.git?ref=v1.2.0... (12s) +2 more

This fixes three problems: stale rows when a message was wider than the terminal, run --all output mixed into the progress text, and progress drawn over the terragrunt catalog TUI.

In CI, with TERM=dumb, and with json logs, Terragrunt writes INFO log lines instead of the progress line.

Operations are reported sooner, and more of them: unit discovery, dependency output fetches, provider caching, waits for new remote state resources, stack generate fetches, and lock waits.

The approval wait in terragrunt login, part of the tg-login experiment, uses the same progress line with or without slow-task-reporting.

A failed Git worktree creation no longer logs that it succeeded.

To learn more, see the experiment documentation.

โš™๏ธ Process Updates

Go bumped to v1.27.4

The version of Golang used to compile the Terragrunt binary has been updated from v1.27.3 to v1.27.4.

None of the fixes in Go v1.27.4 change how Terragrunt behaves.

๐Ÿ› Bug Fixes

--all honors filters outside run

These commands accepted --filter with --all and then acted on every unit:

  • render --all
  • info print --all
  • aws-provider-patch --all

backend bootstrap --all and backend delete --all ignored the queries in a .terragrunt-filters or .terragrunt-excludes file, and render --all ignored --discovery-boundary.

All five now act only on the units the filters select, the way run --all does.

CAS honors the sshkey query parameter

A git source with the sshkey query parameter failed under the Content Addressable Store (CAS), because CAS left the parameter on the address it passed to git.

CAS now removes sshkey from that address and connects with the key.

catalog keeps the clone directory inside its temporary directory

terragrunt catalog clones each repository into a directory named after the last segment of its URL, inside a fresh temporary directory. For a URL ending in /.., with or without a .git suffix, such as https://github.com/example/repo//.., that name was .., so the clone directory was the parent of the temporary directory. For a URL ending in /. it was the temporary directory itself. The run failed with:

refusing to remove clone path "/tmp" outside clone root "/tmp/catalog-<id>"

When the parent already held a .catalog-clone-complete file, the clone was skipped instead, and whatever the parent held was listed as the repository's components.

A name made only of dots now falls back to temp, so the clone directory always stays inside the temporary directory. Any other name is unchanged.

Configuration rewritten during a command is parsed again

Terragrunt caches each parsed configuration file for the length of a command, and parses the file again when its modification time changes. A file rewritten soon after Terragrunt read it can keep the same modification time, as timestamps on Windows and on FAT volumes advance in coarse steps. Terragrunt then kept the cached result, and the rest of the command ran with the old contents.

Terragrunt now also compares the file's size, and compares the contents of any file modified shortly before it was read.

dependency blocks reject a null config_path

An enabled dependency block whose config_path is null is now an error:

/path/to/terragrunt.hcl: dependency db sets config_path to null; set it to a path, or set enabled to false

Terragrunt used to drop these blocks without a warning. A reference to the block failed with This object does not have an attribute named "db", and setting an included block's config_path to null did not remove it: the unit still read the included block's outputs.

To turn a block off, set enabled = false. A disabled block can keep a null config_path, and its mock_outputs are still available to the unit:

dependency "db" {
  config_path  = local.use_db ? "../db" : null
  enabled      = local.use_db
  mock_outputs = { id = "mock" }
}

Overriding an included dependency block replaces it in the run --all queue

A unit that overrode an included dependency block read its outputs from the new config_path, but run --all still ordered it after the included path. The unit waited for that unit and was skipped when it failed. find --dag listed both.

# root.hcl
dependency "db" {
  config_path = "${get_terragrunt_dir()}/../db"
}

# app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

dependency "db" {
  config_path = "../replica"
}

app now depends only on replica. This also applies when a unit sets enabled = false on an included dependency block.

actions = [] in a unit's exclude block overrides an included block under run --all

A unit that set actions = [] to turn off an included exclude block was still excluded from run --all, though terragrunt run plan in the same unit ran:

# root.hcl
exclude {
  if      = true
  actions = ["plan"]
}

# app/terragrunt.hcl
include "root" {
  path = find_in_parent_folders("root.hcl")
}

exclude {
  if      = true
  actions = []
}

run --all now uses the unit's exclude block, as terragrunt run does, so app runs.

exclude blocks with a null or missing if fail run --all before any unit runs

An exclude block whose if was null, or that left if out, excluded nothing from run --all. The unit itself then failed, but the dependencies its exclude_dependencies = true was meant to keep out of the run still ran:

# app/terragrunt.hcl
exclude {
  if                   = local.skip # null
  actions              = ["all"]
  exclude_dependencies = true
}

run --all now fails while it builds the run queue, with the error a single unit run already gave:

Unsuitable value: null value is not allowed

Set if to true or false.

update_source_with_cas works in stacks sourced from OCI registries and HTTP archives

For a unit or stack block sourced from an OCI registry, such as source = "oci://ghcr.io/acme/catalog//stacks/svc?tag=v1", or from an archive at an HTTP URL, Terragrunt copied only the selected directory of the package. Relative sources in that directory that set update_source_with_cas = true stayed as written, so generating the nested stack failed:

ERROR  failed to fetch unit a
  Source:      ../..//units/a
  Destination: .terragrunt-stack/svc/.terragrunt-stack/a
...
Original error: ... relative paths require a module with a pwd

The same catalog served from Git or a local path generated fine.

Stack generation now fetches the whole HTTP archive or OCI module package into the CAS and rewrites nested update_source_with_cas sources to cas:: references. An OCI package is keyed by its manifest digest, so a repeat generation with the same digest links the stored copy without a download.

A literal checksum= pin keys an HTTP archive the same way, and with the offline-cas experiment --cas-offline resolves it from the store; a checksum=file: reference is not answered offline.

As with other CAS-backed sources, the generated files are read-only unless the block sets mutable = true. --no-cas keeps the standard downloader, which copies only the selected directory.

The same checksum= keying applies to every CAS-backed HTTP source, not only stack generation: a terraform.source HTTP URL pinned with checksum= now goes through the CAS too, and a mismatch fails once instead of being downloaded a second time by the standard getter.

For every CAS-backed catalog, Git included, a nested update_source_with_cas source that cannot be rewritten now fails generation instead of falling back to a copy with the relative source left in place.

Under the offline-cas experiment, --cas-offline no longer fetches a source whose recorded probe came from a download that failed. For Git catalogs, the rewritten stack and unit files are now read-only by default like the rest of the tree, and mutable = true makes the copy writable.

Provider cache no longer fails when users share a temp directory

With --provider-cache, users who shared a temp directory also shared its terragrunt folder. After one user created it, init could fail for the others:

mkdir /tmp/terragrunt/providers/archives-032480544: permission denied

On Unix, each user now gets a $TMPDIR/terragrunt-<uid> directory that only they can write to. If that directory is unsafe to use, Terragrunt logs a warning that says why and uses terragrunt/tmp in the user cache directory instead, such as ~/.cache/terragrunt/tmp on Linux.

Provider cache links, root-terragrunt-hcl lookups and GIT_CEILING_DIRECTORIES

  • --provider-cache resolves a relative download_url, shasums_url or shasums_signature_url against the registry response URL, as OpenTofu does.
  • With the root-terragrunt-hcl strict control, find_in_parent_folders fails for ./terragrunt.hcl, ../terragrunt.hcl and other casings of that file, as it does with no argument. So does scaffold when its root file is terragrunt.hcl.
  • Entries after an empty GIT_CEILING_DIRECTORIES entry skip symlink resolution, as in git, even when the empty entry is not first.

remote_state encryption works for units with existing unencrypted state

Adding encryption to a remote_state block for a unit that already had state failed in tofu init, and Terragrunt could not generate the fallback OpenTofu needs to read it:

Error: Error refreshing state

encountered unencrypted payload without unencrypted method configured

Set fallback = { method = "unencrypted" } in the encryption map for one terragrunt apply. OpenTofu reads the plaintext state and writes it back encrypted. Then remove fallback, and optionally set enforced = true so OpenTofu errors instead of writing unencrypted state or plan files.

remote_state {
  backend = "s3"
  config = {
    bucket = "mybucket"
    key    = "path/to/my/key"
    region = "us-east-1"
  }

  encryption = {
    key_provider = "pbkdf2"
    passphrase   = get_env("PBKDF2_PASSPHRASE")
    fallback     = { method = "unencrypted" }
  }
}

See encryption for the generated OpenTofu configuration.

S3 backend bootstrap handles missing encryption and table descriptions

Some S3-compatible object stores answer GetBucketEncryption with HTTP 200 and an empty body instead of a ServerSideEncryptionConfigurationNotFoundError. Terragrunt then crashed with a nil pointer dereference while checking the bucket, which stopped every unit in the run.

Terragrunt now treats a bucket with no encryption document as unencrypted, the same as the not-found error. It lists Bucket Server-Side Encryption in the bucket update prompt, unless skip_bucket_ssencryption or disable_bucket_update is set. With --non-interactive, Terragrunt applies the update without asking.

When DescribeTable returns no table description during lock table setup, Terragrunt now fails the unit with an error that names the table and points at dynamodb_endpoint. Before, it crashed.

scaffold resolves relative paths against the working directory

terragrunt scaffold --output-folder live/vpc wrote into live/vpc under the directory the shell was in, not under --working-dir, and the same went for a relative --var-file. Both are now taken from the working directory, as the module URL already was. An absolute path is used as given.

The warning that the directory being scaffolded into is not empty now inspects the output folder, since that is where the files land.

A module named by a relative local path, such as ../modules/vpc, is downloaded relative to the working directory but was written into the generated terraform { source } as typed, where the unit reads it relative to its own directory. The two agreed only when --output-folder was unset. The generated source is now written relative to the output folder, so the unit points at the module that was scaffolded from. Absolute paths and remote URLs are written as before.

Stacks that read a file in values are matched by reading filters

A stack that read a file in a unit or stack block, rather than in locals, was not recorded as reading it:

# live/app/terragrunt.stack.hcl

unit "app" {
  source = "${get_repo_root()}/catalog/units/app"
  path   = "app"

  values = {
    message = yamldecode(file("${get_repo_root()}/shared/config.yml")).message
  }
}

--filter 'reading=shared/config.yml' did not match the stack, and a Git filter such as --filter '[main...HEAD]' did not regenerate it when only shared/config.yml changed, so its units never ran with the new value. Moving the same read into locals worked.

Terragrunt now tracks reads anywhere in a stack file, except inside autoinclude blocks. See Files read by stacks.

OpenTelemetry command span reports the real command, arguments, and directory

The span that wraps each Terragrunt command had a trailing space in its name and empty or unreadable attributes. A terragrunt run --all -- plan exported:

{
  "name": "plan ",
  "attributes": { "args": "&{ [] [] []}", "dir": "", "terraformCommand": "" }
}

The span is now named plan, args is a list of the arguments passed to OpenTofu/Terraform, and dir is the working directory. Commands that don't run OpenTofu/Terraform, such as find, report only dir. The tofu_cli_args attribute of runner_pool_task and the args attribute of run_<binary> are lists too, on both spans and metrics, where before they were strings.

Three attributes have new names, so update any queries that filter on them:

  • terraformCommand is now tofu_command.
  • terraform_command is now tofu_command.
  • terraform_cli_args is now tofu_cli_args.

The <command>_duration metric, such as plan_duration, now has one label, dir, set to the absolute working directory. Before, dir was empty unless you set --working-dir or TG_WORKING_DIR. Each working directory now gets its own metric series. The metric's args and terraformCommand labels are gone. They never held usable values, so remove them from any queries that filter on them.

Spans, metrics, and log records also report the Terragrunt version as their instrumentation scope version, which was empty.

See OpenTelemetry for how to export telemetry.

Pull Requests

โœจ Features

  • feat: add terraform.no_dot_terragrunt_cache to run units without .terragrunt-cache by @denis256 in #7093
  • feat: Adding catalog tool to the mcp command by @yhakbar in #7234
  • feat: Adding scaffold tool to the mcp command by @yhakbar in #7253
  • feat: Adding docs capability to the mcp command by @yhakbar in #7256
  • feat: Adding variables block by @yhakbar in #7238
  • feat: Adding fmt tool to the mcp command by @yhakbar in #7239

๐Ÿ› Bug Fixes

  • fix: Adding size as another fast change indicator by @yhakbar in #7193
  • fix: Adding racy mtime check by @yhakbar in #7195
  • fix: Fixing flag env vars by @yhakbar in #7217
  • fix: Adding remote state encryption fallback by @yhakbar in #7223
  • fix(provider-cache): stop permission errors on shared temp dir by @denis256 in #7233
  • fix(telemetry): make otel-logs export reliable by @denis256 in #7219
  • fix: Fixing stacks reading tracking for values by @yhakbar in #7226
  • fix: Fixing scaffold output directory relativization by @yhakbar in #7247
  • fix: Preventing S3 backend bootstrap crash on missing encryption or table description by @denis256 in #7203
  • fix(catalog): keep clone directory inside its temp dir by @denis256 in #7262
  • fix: Fixing support for the sshkey parameter while using CAS by @yhakbar in #7265
  • fix: Fixing telemetry root span attributes by @yhakbar in #7250
  • fix: Sharing GitHub API lookups across the docs build by @yhakbar in #7273
  • fix: Rejecting a null or missing exclude if during discovery by @yhakbar in #7283
  • fix: Fixing partial parse consistency by @yhakbar in #7278
  • fix(stacks): rewrite update_source_with_cas in OCI and HTTP archive stacks by @denis256 in #7272
  • fix: root file check, proxy links and git ceiling by @denis256 in #7271
  • fix: Plumb through --filter for render by @yhakbar in #7293

๐ŸŽ๏ธ Performance

  • perf: Make relationship discovery linear in unit count by @yhakbar in #7201
  • perf: Memoize symlink resolution in discovery by @yhakbar in #7005
  • perf: Setting up rewrite implementation of the config package by @yhakbar in #7045
  • perf: Deferring dependency output resolution in the config rewrite by @yhakbar in #7049
  • perf: Only construct stack funcs for stack dependencies by @yhakbar in #7202
  • perf: Pre-allocate slices with known lengths by @yhakbar in #7266
  • perf: Config rewrite parse store by @yhakbar in #7188
  • perf: Plumbing down parse store by @yhakbar in #7282
  • perf: Reading run configs through the parse store by @yhakbar in #7292

๐Ÿ“– Documentation

  • docs: clean up released version gates for v1.2.1 by @github-actions[bot] in #7200
  • docs: Adding suggestion for version-specific docs by @yhakbar in #7215
  • docs: fix Terragrunt GitHub Discussions link on support page by @lv201 in #7216
  • docs: Capturing more env vars for flags by @yhakbar in #7218
  • docs: Fixing short SHAs in install script by @yhakbar in #7227
  • docs: Moving HCL blocks, attributes, and functions to data-driven pages by @yhakbar in #7237
  • docs: Fixing llms-full.txt generation by getting rid of starlight-llms-txt by @yhakbar in #7242
  • docs: Cleaning up function docs display by @yhakbar in #7246
  • docs: Redirecting old HCL subsection anchors to their new pages by @yhakbar in #7249
  • docs: Fixing broken markdown route build by @yhakbar in #7255
  • docs: Moving more HCL attribute to data files by @yhakbar in #7268
  • docs: Splitting the HCL overview into units and stacks pages by @yhakbar in #7274
  • docs: Moving stack configuration blocks to data files by @yhakbar in #7285
  • docs: Moving terraform and remote_state HCL block docs to their own pages by @yhakbar in #7288
  • docs: updating changelog category order by @yhakbar in #7301
  • docs: Addressing some changelog gaps for v1.2.2 by @yhakbar in #7302

โœ… Tests

  • test: raise coverage in spinner, controls, git, worktrees and hcl format by @denis256 in #7224

๐Ÿงน Chores

๐Ÿ“ Other Changes

  • tip: Adding inputs-read-not-tracked tip by @yhakbar in #7263
  • strict: Adding the cas-source-inside-stack strict control by @yhakbar in #7290

Don't miss a new terragrunt release

NewReleases is sending notifications on new releases.