docs: def changes(since, out_file, eager):
      """Show changes since a specific date."""
      root = get_root()
      history_data = defaultdict(lambda: {'lines': deque(), 'releasers': set()})
  
      with chdir(root):
          result = run_command(
              (
                  'git log "--pretty=format:%H %s" --date-order --date=iso8601 '
                  '--since="{}T00:00:00" */CHANGELOG.md'.format(since)
              ),
              capture=True,
              check=True,
          )
  
          for result_line in result.stdout.splitlines():
              commit_hash, commit_subject = result_line.split(' ', 1)
  
              if not eager and 'release' not in commit_subject.lower():
                  continue
  
              result = run_command(
                  'git show "--pretty=format:%an%n" -U0 {} */CHANGELOG.md'.format(commit_hash), capture=True, check=True
              )
  
              # Example:
              #
              # <AUTHOR NAME>
              # diff --git a/<INTEGRATION NAME 1>/CHANGELOG.md b/<INTEGRATION NAME 1>/CHANGELOG.md
              # index 89b5a3441..9534019a9 100644
              # --- a/<INTEGRATION NAME 1>/CHANGELOG.md
              # +++ b/<INTEGRATION NAME 1>/CHANGELOG.md
              # @@ -2,0 +3,5 @@
              # +## <RELEASE VERSION> / <RELEASE DATE>
              # +
              # +* <ENTRY>
              # +* <ENTRY>
              # +
              # diff --git a/<INTEGRATION NAME 2>/CHANGELOG.md b/<INTEGRATION NAME 2>/CHANGELOG.md
              # index 89b5a3441..9534019a9 100644
              # --- a/<INTEGRATION NAME 2>/CHANGELOG.md
              # +++ b/<INTEGRATION NAME 2>/CHANGELOG.md
              # @@ -2,0 +3,4 @@
              # +## <RELEASE VERSION> / <RELEASE DATE>
              # +
              # +* <ENTRY>
              # +
              lines = deque(result.stdout.splitlines())
              author_name = lines.popleft().strip()
  
              patches = []
              for line in lines:
                  if line:
                      # New patch
                      if line.startswith('diff --git'):
                          patches.append([])
                      patches[-1].append(line)
  
              for patch in patches:
                  integration = patch[0].split('/')[-2].strip()
                  history_data[integration]['releasers'].add(author_name)
  
                  additions = deque()
                  for line in reversed(patch):
                      if line.startswith('+'):
                          line = line[1:]
                          # Demote releases to h3
                          if line.startswith('##'):
                              line = '#{}'.format(line)
                          additions.append(line)
                      elif line.startswith('@@'):
                          break
  
                  # Get rid of the header for new integrations
                  if additions[-1].startswith('# '):
                      additions.pop()
  
                  # Get rid of blank lines to ensure consistency
                  while not additions[0].strip():
                      additions.popleft()
                  while not additions[-1].strip():
                      additions.pop()
  
                  history_data[integration]['lines'].appendleft('')
                  history_data[integration]['lines'].extendleft(additions)
  
      output_lines = ['# Changes since {}'.format(since), '']
  
      for integration, history in sorted(iteritems(history_data)):
          display_name = load_manifest(integration).get('display_name', integration)
          output_lines.append('## {}'.format(display_name))
          output_lines.append('released by: {}'.format(', '.join(sorted(history['releasers']))))
  
          output_lines.append('')
          output_lines.extend(history['lines'])
  
      output = '\n'.join(output_lines)
  
      if out_file:
          write_file(out_file, output)
      else:
          echo_info(output)