Skip to content

Commit 7b01d87

Browse files
committed
feat: refactor render -> renderTemplate function and update wiki usage template handling
1 parent 6fe0e7c commit 7b01d87

File tree

14 files changed

+349
-161
lines changed

14 files changed

+349
-161
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ jobs:
4949
disable-wiki: false
5050
wiki-sidebar-changelog-max: 10
5151
delete-legacy-tags: false # Note: We don't want to delete tags in this repository
52-
terraform-docs-version: v0.19.0
53-
module-path-ignore: tf-modules/kms/examples/complete
52+
terraform-docs-version: v0.20.0
53+
module-path-ignore: tf-modules/kms/examples/complete,tf-modules/zoo,tf-modules/animal,tf-modules/s3-bucket-object
5454
module-change-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**,examples/**
5555
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
5656
use-ssh-source-format: true

README.md

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,12 @@ configuring the following optional input parameters as needed.
194194
| `delete-legacy-tags` | Specifies a boolean that determines whether tags and releases from Terraform modules that have been deleted should be automatically removed | `true` |
195195
| `disable-wiki` | Whether to disable wiki generation for Terraform modules | `false` |
196196
| `wiki-sidebar-changelog-max` | An integer that specifies how many changelog entries are displayed in the sidebar per module | `5` |
197-
| `wiki-usage-template` | A raw, multi-line string to override the default 'Usage' section in the generated wiki. Allows using variables like {{module_name}}, {{latest_tag}}, {{latest_tag_version_number}} and more.<br><sub>[Read more here](#configuring-the-usage-template)</sub> | [See action.yml](https://github.com/polleuretan/terraform-module-releaser/blob/main/action.yml#L108) |
197+
| `wiki-usage-template` | A raw, multi-line string to override the default 'Usage' section in the generated wiki. Allows using variables like {{module_name}}, {{latest_tag}}, {{latest_tag_version_number}} and more.<br><sub>[Read more here](#configuring-the-wiki-usage-template)</sub> | [See action.yml](https://github.com/polleuretan/terraform-module-releaser/blob/main/action.yml#L108) |
198198
| `disable-branding` | Controls whether a small branding link to the action's repository is added to PR comments. Recommended to leave enabled to support OSS. | `false` |
199199
| `module-path-ignore` | Comma-separated list of module paths to completely ignore. Modules matching any pattern here are excluded from all versioning, releases, and documentation.<br><sub>[Read more here](#understanding-the-filtering-options)</sub> | `` (empty string) |
200200
| `module-change-exclude-patterns` | Comma-separated list of file patterns (relative to each module) to exclude from triggering version changes. Lets you release a module but control which files inside it do not force a version bump.<br><sub>[Read more here](#understanding-the-filtering-options)</sub> | `.gitignore,*.md,*.tftest.hcl,tests/**` |
201201
| `module-asset-exclude-patterns` | A comma-separated list of file patterns to exclude when bundling a Terraform module for tag/release. Patterns follow glob syntax (e.g., `tests/\*\*`) and are relative to each Terraform module directory. Files matching these patterns will be excluded from the bundled output. | `.gitignore,*.md,*.tftest.hcl,tests/**` |
202-
| `use-ssh-source-format` | If enabled, all links to source code in generated Wiki documentation will use SSH standard format (e.g., `git::ssh://[email protected]/owner/repo.git`) instead of HTTPS format (`git::https://github.com/owner/repo.git`) | `false` |
202+
| `use-ssh-source-format` | If enabled, all links to source code in generated Wiki documentation will use SSH format (e.g., `git::ssh://[email protected]/owner/repo.git`) instead of HTTPS format (`git::https://github.com/owner/repo.git`) | `false` |
203203
| `tag-directory-separator` | Character used to separate directory path components in Git tags. Supports `/`, `-`, `_`, or `.` | `/` |
204204
| `use-version-prefix` | Whether to include the 'v' prefix on version tags (e.g., v1.2.3 vs 1.2.3) | `true` |
205205

@@ -284,7 +284,7 @@ similar to those used in `.gitignore` files. For more details on the pattern mat
284284
[source code](https://github.com/techpivot/terraform-module-releaser/blob/main/src/utils/file.ts) or visit the
285285
[minimatch documentation](https://github.com/isaacs/minimatch).
286286

287-
### Configuring the Usage Template
287+
### Configuring the Wiki Usage Template
288288

289289
The `wiki-usage-template` input allows you to customize the "Usage" section of the generated wiki page for each module.
290290
You can use the following dynamic variables in your template:
@@ -293,8 +293,8 @@ You can use the following dynamic variables in your template:
293293
| ------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------- |
294294
| `{{module_name}}` | The name of the module. | `aws/s3-bucket` |
295295
| `{{latest_tag}}` | The latest Git tag for the module. | `aws/s3-bucket/v1.2.3` |
296-
| `{{latest_tag_version_number}}` | The version number of the latest tag. | `1.2.3` |
297-
| `{{module_source}}` | The Git source URL for the module, respecting the `use-ssh-source-format` input. | `git::https://github.com/owner/repo.git` |
296+
| `{{latest_tag_version_number}}` | The version number of the latest tag (Always excludes any `v` prefix) | `1.2.3` |
297+
| `{{module_source}}` | The Git source URL for the module with git:: prefix, respecting the `use-ssh-source-format` input. | `git::ssh://github.com/techpivot/terraform-module-releaser.git` |
298298
| `{{module_name_terraform}}` | A Terraform-safe version of the module name (e.g., special characters replaced with underscores). | `aws_s3_bucket` |
299299

300300
### Example Usage with Inputs
@@ -325,29 +325,31 @@ jobs:
325325
minor-keywords: feat,feature
326326
patch-keywords: fix,chore,docs
327327
default-first-tag: v1.0.0
328-
terraform-docs-version: v0.19.0
328+
terraform-docs-version: v0.20.0
329329
delete-legacy-tags: true
330330
disable-wiki: false
331331
wiki-sidebar-changelog-max: 10
332332
module-path-ignore: path/to/ignore1,path/to/ignore2
333333
module-change-exclude-patterns: .gitignore,*.md,docs/**,examples/**,*.tftest.hcl,tests/**
334334
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
335-
use-ssh-source-format: false
335+
use-ssh-source-format: true
336+
tag-directory-separator: /
337+
use-version-prefix: true
336338
wiki-usage-template: |
337-
# My Custom Usage Instructions
339+
This is a custom wiki usage block that supports markdown.
338340
339-
This is a custom usage block.
340-
341-
You can add any markdown you want here.
342-
343-
And use variables like {{module_name}}, {{latest_tag}}, {{latest_tag_version_number}},
344-
{{module_source}} and {{module_name_terraform}}.
341+
The following variables are supported:
342+
- {{module_name}}
343+
- {{latest_tag}}
344+
- {{latest_tag_version_number}}
345+
- {{module_source}}
346+
- {{module_name_terraform}}
345347
346348
```hcl
347349
module "{{module_name_terraform}}" {
348-
source = "{{module_source}}?ref={{latest_tag}}"
349-
version = "{{latest_tag_version_number}}"
350-
# ...
350+
source = "{{module_source}}?ref={{latest_tag}}"
351+
352+
# See inputs below for additional required parameters
351353
}
352354
```
353355
````
@@ -369,6 +371,8 @@ The following outputs are available from this action:
369371

370372
```json
371373
{
374+
"changed-module-names": ["aws/vpc"],
375+
"changed-module-paths": ["/home/runner/work/terraform-module-releaser/terraform-module-releaser/aws/vpc"],
372376
"changed-modules-map": {
373377
"aws/vpc": {
374378
"path": "modules/aws/vpc",
@@ -377,16 +381,21 @@ The following outputs are available from this action:
377381
"releaseType": "minor"
378382
}
379383
},
384+
"all-module-names": ["aws/s3", "aws/vpc"],
385+
"all-module-paths": [
386+
"/home/runner/work/terraform-module-releaser/terraform-module-releaser/aws/s3",
387+
"/home/runner/work/terraform-module-releaser/terraform-module-releaser/aws/vpc"
388+
],
380389
"all-modules-map": {
381-
"aws/vpc": {
382-
"path": "modules/aws/vpc",
383-
"latestTag": "aws/vpc/v1.0.0",
384-
"latestTagVersion": "v1.0.0"
385-
},
386390
"aws/s3": {
387391
"path": "modules/aws/s3",
388392
"latestTag": "aws/s3/v2.1.0",
389393
"latestTagVersion": "v2.1.0"
394+
},
395+
"aws/vpc": {
396+
"path": "modules/aws/vpc",
397+
"latestTag": "aws/vpc/v1.0.0",
398+
"latestTagVersion": "v1.0.0"
390399
}
391400
}
392401
}

__tests__/templating.test.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.

__tests__/utils/metadata.test.ts

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ACTION_INPUTS, createConfigFromInputs } from '@/utils/metadata';
22
import type { ActionInputMetadata } from '@/types';
3-
import { getBooleanInput, getInput } from '@actions/core';
3+
import { getInput } from '@actions/core';
44
import { describe, expect, it, vi } from 'vitest';
55

66
describe('utils/metadata', () => {
@@ -15,6 +15,7 @@ describe('utils/metadata', () => {
1515
'delete-legacy-tags',
1616
'disable-wiki',
1717
'wiki-sidebar-changelog-max',
18+
'wiki-usage-template',
1819
'disable-branding',
1920
'module-path-ignore',
2021
'module-change-exclude-patterns',
@@ -167,59 +168,5 @@ describe('utils/metadata', () => {
167168
`Failed to process input 'major-keywords': ${String(errorObject)}`,
168169
);
169170
});
170-
171-
it('should process all input types correctly', () => {
172-
// Mock the GitHub Actions core functions
173-
vi.mocked(getInput).mockImplementation((name) => {
174-
const mockValues: Record<string, string> = {
175-
'major-keywords': 'breaking,major',
176-
'minor-keywords': 'feat,feature',
177-
'patch-keywords': 'fix,chore',
178-
'default-first-tag': 'v1.0.0',
179-
'terraform-docs-version': 'v0.20.0',
180-
'wiki-sidebar-changelog-max': '5',
181-
'module-path-ignore': '',
182-
'module-change-exclude-patterns': '*.md,tests/**',
183-
'module-asset-exclude-patterns': '*.md,tests/**',
184-
github_token: 'fake-token',
185-
'tag-directory-separator': '/',
186-
'use-ssh-source-format': 'false',
187-
};
188-
return mockValues[name] || '';
189-
});
190-
191-
vi.mocked(getBooleanInput).mockImplementation((name) => {
192-
const mockBooleans: Record<string, boolean> = {
193-
'delete-legacy-tags': true,
194-
'disable-wiki': false,
195-
'disable-branding': false,
196-
'use-ssh-source-format': false,
197-
'use-version-prefix': true,
198-
};
199-
return mockBooleans[name] || false;
200-
});
201-
202-
const config = createConfigFromInputs();
203-
204-
// Verify all config properties are set
205-
expect(config).toEqual({
206-
majorKeywords: ['breaking', 'major'],
207-
minorKeywords: ['feat', 'feature'],
208-
patchKeywords: ['fix', 'chore'],
209-
defaultFirstTag: 'v1.0.0',
210-
terraformDocsVersion: 'v0.20.0',
211-
deleteLegacyTags: true,
212-
disableWiki: false,
213-
wikiSidebarChangelogMax: 5,
214-
disableBranding: false,
215-
modulePathIgnore: [],
216-
moduleChangeExcludePatterns: ['*.md', 'tests/**'],
217-
moduleAssetExcludePatterns: ['*.md', 'tests/**'],
218-
useSSHSourceFormat: false,
219-
githubToken: 'fake-token',
220-
tagDirectorySeparator: '/',
221-
useVersionPrefix: true,
222-
});
223-
});
224171
});
225172
});

__tests__/utils/string.test.ts

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { removeLeadingCharacters, removeTrailingCharacters } from '@/utils/string';
1+
import { removeLeadingCharacters, removeTrailingCharacters, renderTemplate } from '@/utils/string';
22
import { describe, expect, it } from 'vitest';
33

44
describe('utils/string', () => {
@@ -91,4 +91,90 @@ describe('utils/string', () => {
9191
expect(removeTrailingCharacters('example-_./', ['/', '.', '_', '-'])).toBe('example');
9292
});
9393
});
94+
95+
describe('renderTemplate', () => {
96+
it('should replace a single placeholder', () => {
97+
const template = 'Hello, {{name}}!';
98+
const variables = { name: 'World' };
99+
const result = renderTemplate(template, variables);
100+
expect(result).toBe('Hello, World!');
101+
});
102+
103+
it('should replace multiple placeholders', () => {
104+
const template = '{{greeting}}, {{name}}!';
105+
const variables = { greeting: 'Hi', name: 'There' };
106+
const result = renderTemplate(template, variables);
107+
expect(result).toBe('Hi, There!');
108+
});
109+
110+
it('should handle templates with no placeholders', () => {
111+
const template = 'Just a plain string.';
112+
const variables = { name: 'World' };
113+
const result = renderTemplate(template, variables);
114+
expect(result).toBe('Just a plain string.');
115+
});
116+
117+
it('should handle empty string values', () => {
118+
const template = 'A{{key}}B';
119+
const variables = { key: '' };
120+
const result = renderTemplate(template, variables);
121+
expect(result).toBe('AB');
122+
});
123+
124+
it('should leave unmapped placeholders untouched', () => {
125+
const template = 'Hello, {{name}} and {{unmapped}}!';
126+
const variables = { name: 'World' };
127+
const result = renderTemplate(template, variables);
128+
expect(result).toBe('Hello, World and {{unmapped}}!');
129+
});
130+
131+
it('should handle complex templates with multiple variables', () => {
132+
const template = 'Module: {{module}}, Version: {{version}}, Author: {{author}}';
133+
const variables = { module: 'vpc-endpoint', version: '1.0.0', author: 'TechPivot' };
134+
const result = renderTemplate(template, variables);
135+
expect(result).toBe('Module: vpc-endpoint, Version: 1.0.0, Author: TechPivot');
136+
});
137+
138+
it('should handle numeric values as strings', () => {
139+
const template = 'Port: {{port}}, Count: {{count}}';
140+
const variables = { port: '8080', count: '3' };
141+
const result = renderTemplate(template, variables);
142+
expect(result).toBe('Port: 8080, Count: 3');
143+
});
144+
145+
it('should handle special characters in values', () => {
146+
const template = 'Path: {{path}}, Command: {{cmd}}';
147+
const variables = { path: '/opt/bin/terraform', cmd: 'terraform init -backend=false' };
148+
const result = renderTemplate(template, variables);
149+
expect(result).toBe('Path: /opt/bin/terraform, Command: terraform init -backend=false');
150+
});
151+
152+
it('should handle empty template', () => {
153+
const template = '';
154+
const variables = { name: 'World' };
155+
const result = renderTemplate(template, variables);
156+
expect(result).toBe('');
157+
});
158+
159+
it('should handle empty variables object', () => {
160+
const template = 'Hello, {{name}}!';
161+
const variables = {};
162+
const result = renderTemplate(template, variables);
163+
expect(result).toBe('Hello, {{name}}!');
164+
});
165+
166+
it('should handle placeholders with different casing', () => {
167+
const template = 'Hello, {{Name}} and {{NAME}}!';
168+
const variables = { Name: 'World', NAME: 'UNIVERSE' };
169+
const result = renderTemplate(template, variables);
170+
expect(result).toBe('Hello, World and UNIVERSE!');
171+
});
172+
173+
it('should handle placeholders with numbers', () => {
174+
const template = 'Item {{item1}} and {{item2}}';
175+
const variables = { item1: 'first', item2: 'second' };
176+
const result = renderTemplate(template, variables);
177+
expect(result).toBe('Item first and second');
178+
});
179+
});
94180
});

0 commit comments

Comments
 (0)