Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 2, 2025

Overview

This PR implements a new module-ref-mode configuration option that controls how Terraform module usage examples reference versions in generated wiki documentation. This addresses the module removal scenario described in #171 where tags can be deleted, breaking references for users of outdated module versions.

Problem Statement

When a Terraform module is decommissioned or renamed, all associated tags and releases are typically removed by default. This creates a critical issue: users referencing specific module versions lose their reference points when tags are deleted, potentially breaking their infrastructure. While the delete-legacy-tags parameter can preserve tags, an alternative approach is needed for environments using tools like Renovate that support digest pinning.

As suggested in #171, commit SHAs provide an immutable reference that cannot be easily deleted from GitHub, unlike tags. However, SHAs alone are not human-readable, making it difficult to understand which version is being used.

Solution

This PR adds a module-ref-mode input parameter with two modes:

Tag Mode (default - preserves current behavior)

module "aws_vpc_endpoint" {
  source = "git::ssh://[email protected]/owner/repo.git?ref=aws/vpc-endpoint/v1.1.3"
}

SHA Mode (new - supports Renovate digest pinning)

module "aws_vpc_endpoint" {
  source = "git::ssh://[email protected]/owner/repo.git?ref=ee4e1294eb806447b36eaa5e000947449eab4fc4" # aws/vpc-endpoint/v1.1.3
}

When SHA mode is enabled, the action uses commit SHAs from the GitHub API for the ref parameter in generated documentation while preserving the tag name as a comment for human readability.

Key Features

  • Immutable References: Commit SHAs cannot be deleted from GitHub as easily as tags
  • Renovate Compatible: Works with Renovate's digest pinning strategy (see SpotOnInc/renovate-config for examples)
  • API-Based: SHAs fetched directly from GitHub API (tag.commit.sha and release.target_commitish)
  • Flexible Template Variables: {{latest_tag}} always shows the tag name; {{ref}} contains the actual reference (tag or SHA); {{ref_comment}} provides tag version as inline comment in SHA mode
  • Fully Backward Compatible: Default behavior unchanged; tag/release creation unaffected
  • Only Documentation Changes: Only affects generated wiki content, not tag or release creation

Implementation Details

New Configuration

  • Input: module-ref-mode
  • Type: String
  • Values: "tag" | "sha"
  • Default: "tag"
  • Required: Yes (with default)

Template Variables

  • {{latest_tag}}: Always contains the tag name (e.g., aws/vpc-endpoint/v1.1.3)
  • {{ref}}: Contains the actual ref value - either tag name or commit SHA depending on mode
  • {{ref_comment}}: Empty string in tag mode; # {version} in SHA mode for human-readable reference
  • {{latest_tag_version_number}}: Version number without prefix
  • {{module_source}}: Git source URL
  • {{module_name_terraform}}: Terraform-safe module name

Architecture Changes

  • GitHubTag Type: New type with name and commitSHA fields, mirroring GitHubRelease pattern
  • TerraformModule: Internally stores GitHubTag[] instead of string arrays, consistent with release handling
  • Tag Storage: Commit SHAs populated directly from GitHub API's tag.commit.sha field during tag retrieval
  • Release Creation: SHAs extracted from repos.createRelease response's target_commitish field
  • Single getAllTags(): Simplified API with one method returning GitHubTag[]

Type Safety

  • Constants: MODULE_REF_MODE_TAG, MODULE_REF_MODE_SHA, ALLOWED_MODULE_REF_MODES
  • Validation uses ALLOWED_MODULE_REF_MODES.includes() for runtime checking
  • Type inference from const assertions eliminates need for explicit type guards

Testing

  • Config validation tests (invalid values rejected with clear errors)
  • SHA storage and retrieval tests with GitHubTag structure
  • Tag API mock structure updated to include commit SHA
  • Error handling and fallback behavior validated
  • Integration with existing test infrastructure
  • All 480 tests passing (11 skipped requiring GITHUB_TOKEN)

Documentation

  • Updated README.md with new parameter in input parameters table
  • Updated template variables documentation to reflect new {{ref}} and {{ref_comment}} variables
  • Updated example configuration with new parameter
  • Enhanced action.yml input description with usage details
  • Variable ordering in examples: latest_tag, latest_tag_version_number, ref, ref_comment

Breaking Changes

None. This is a fully backward-compatible addition with the default behavior unchanged.

Example Usage

- uses: techpivot/terraform-module-releaser@v1
  with:
    module-ref-mode: sha  # Enable SHA mode for Renovate compatibility
    use-ssh-source-format: true

Related Issues

Closes #171

Credits

Thanks to @MaxymVlasov for the detailed suggestion and example configuration in #168!

Original prompt

This section details on the original issue you should resolve

<issue_title>Try to use digests not tags via Renovate, to deal with module removal issues</issue_title>
<issue_description>Also, hint about

2.1 Tag removal impact

By default, when decommissioning a module, all tags and releases are removed. This means users of outdated versions would indeed lose their reference points, potentially breaking their infrastructure. However, this behavior can be modified.

2.2 Mitigation for tag deletion

You've identified a critical concern. When a tag is deleted, accessing the specific commit becomes difficult since you'd need to know the exact SHA. We can address this by using the delete-legacy-tags parameter (documented at techpivot/terraform-module-releaser).

Setting delete-legacy-tags to false will preserve all existing tags/releases, allowing users of the old module to continue using it even after decommissioning or renaming. This provides a transition period for migration.

You can note in docs that users can pin their modules to digests using Renovate (here example config - SpotOnInc/renovate-config), so they will not lose access to version if tag will be removed.

I am not sure that it will work fine with your tagging strategy, but you can try.

Originally posted by @MaxymVlasov in #168

That should end in something like this:

module "aws_vpc_endpoint" {
  source = "git::ssh://[email protected]/techpivot/terraform-modules-demo.git?ref=ee4e1294eb806447b36eaa5e000947449eab4fc4" # aws/vpc-endpoint/v1.1.3
}

so, you'll still have tag as human-readable reference at the end of ref, but actually point to commit sha, which can't be removed from Github so easy as tag deletion

And yes, Renovate will automatically update

source = "git::ssh://[email protected]/techpivot/terraform-modules-demo.git?ref=aws/vpc-endpoint/v1.1.3"

to

source = "git::ssh://[email protected]/techpivot/terraform-modules-demo.git?ref=ee4e1294eb806447b36eaa5e000947449eab4fc4" # aws/vpc-endpoint/v1.1.3

But it could stuck as there are so many different versions for different modules, that why it requires future investigation, and could require some custom configs

</issue_description>

<agent_instructions>Implement config option to control how Terraform module usage examples (WIKI/doc generation) choose the ref: tag vs commit SHA. Source issue: #171.

Requirements:

New config key: module_ref_mode with allowed values "tag" | "sha". Default: "tag" (must preserve current behavior).
When "tag": no change (use existing tag in ?ref=).
When "sha": resolve the commit SHA for the tag and substitute the SHA in ?ref= for all generated module examples. Tag/release creation process remains unchanged (still create tags/releases exactly as before). Only documentation output changes.
Validation: fail fast if value not in allowed set. Use TypeScript style consistent with repo:
Define string literal union type: type ModuleRefMode = "tag" | "sha"
Export runtime constants (e.g. const MODULE_REF_MODE_TAG = "tag" as const; const MODULE_REF_MODE_SHA = "sha" as const) and an ALLOWED_MODULE_REF_MODES array for validation.
Add a guard function isModuleRefMode(val: unknown): val is ModuleRefMode.
Config loading:
If key absent -> default "tag".
If present -> validate; on failure throw descriptive error: "Invalid module_ref_mode ''. Allowed: tag | sha".
SHA resolution (sha mode):
For each tag used in examples, get commit SHA (prefer local git: git rev-parse ).
Cache results in a Map to avoid repeated calls.
If resolution fails, abort with clear error (do NOT silently fallback to tag).
WIKI/doc generation:
Centralize ref selection in a helper: getDisplayRef(tag, mode).
Replace existing direct tag usage with call to helper.
Tests:
Default (no key) => tag output.
Explicit "tag" => tag output.
"sha" => 40-char hex SHA replaces tag.
Invalid value => throws.
Simulated missing tag in sha mode => error.
Documentation:
Update README / config docs: describe module_ref_mode (purpose, values, default, examples).
Note rationale: SHA mode improves immutability if tags later deleted.
No changes to release logic or tag deletion settings; only doc ref selection.
Commit message suggestion: feat: add module_ref_mode (tag|sha) for WIKI module reference style
Acceptance:
Backward compatibility: unchanged output when omitted.
Deterministic SHA substitution in sha mode.
Tests pass.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@virgofx This is a great suggestion. I love this. Thanks for documenting this so thoroughly! I'll ping you when I have something close and ready to test in next release. <...
Fixes #171

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@Copilot Copilot AI changed the title [WIP] Try to use digests not tags via Renovate, to deal with module removal issues Add module-ref-mode config to support commit SHA references in wiki documentation Oct 2, 2025
@Copilot Copilot AI requested a review from virgofx October 2, 2025 05:27
Copilot finished work on behalf of virgofx October 2, 2025 05:27
@virgofx
Copy link
Member

virgofx commented Oct 2, 2025

@copilot

Lets:

  • Leave latest_tag as is. Revert modifications to that.
  • Remove latest_tag_comment. Instead, add the actual ref as variable {ref} and we'll change the default wiki template to use ref. This way, we always output both sha and tag as variables for consumers to decide. We'll prepopulate the {ref} with the value of one or the other depending on flag.
  • Let's also move the sha as a value inside TerraformModule such that we can populate from getting Tags/Releases initially for historical ones and then for the newly created ones via createTaggedReleases, let's call out into the git to get that value either immediately after or see if the original GITHUB API provides that value in a response. If it does (which I believe so), we can just remove the GIT part for getting the tags and just rely on the API.
  • For the validation, let's just use ALLOWED_MODULE_REF_MODES and remove isModuleRefMode and ModuleRefMode

Separately, in the PR, you mention "✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo."

Can you confirm whether or not you are able to read and leverage the instructions file: .github/copilot-instructions.md?

Copy link
Contributor Author

Copilot AI commented Oct 2, 2025

@copilot

Lets:
...

Done in eba997a. Changes implemented:

  1. latest_tag reverted - now always shows the tag name
  2. latest_tag_comment removed
  3. ✅ Added new {ref} variable that contains the actual ref (tag or SHA based on mode)
  4. ✅ SHA storage moved to TerraformModule class with new methods: setTagCommitSHA(), getTagCommitSHA(), getLatestTagCommitSHA()
  5. ✅ SHAs now fetched from GitHub API (tag.commit.sha) when calling getAllTagsWithCommitSHA()
  6. ✅ For newly created releases, SHA stored from API response's target_commitish field
  7. ✅ Default wiki template updated to use ?ref={{ref}}
  8. ✅ Removed isModuleRefMode() and ModuleRefMode type
  9. ✅ Validation now uses ALLOWED_MODULE_REF_MODES.includes()
  10. ✅ Removed git.ts utility - no longer using git rev-parse

Re: copilot-instructions.md - Yes, I can read and leverage .github/copilot-instructions.md. I used it throughout this implementation (referenced the testing commands, build process, and repo structure from it).

Copilot finished work on behalf of virgofx October 2, 2025 05:58
@virgofx
Copy link
Member

virgofx commented Oct 2, 2025

@copilot

Lets:

  • ensure that allTags is consistent with releases in that it returns an array of GitHubTag types. Add this new type in the appropriate types.
  • Just update to have a single getTags() without having additional methods. We'll proxy the SHA everywhere from the original API calls for getting tags which include SHA output.
  • Similarly update TerraformModule to just internalize tags using the new type (similar to how Releases are done). This should simply logic, reduce the need for extra methods. Mirror what we did for releases.
  • remove the extra comment " // Second pass: Sort using pre-extracted versions" in setReleases
  • improve setTags() to mirror what setReleases() does. This will ultimately force us to update a lot of the tests that call into setTags() we do have a mock helper, it should be able to retain a similar method signature for the tests and automatically generate SHAs

Copy link
Contributor Author

Copilot AI commented Oct 2, 2025

@copilot

Lets:
...

Done in 660bfc6. Changes implemented:

  1. ✅ Created GitHubTag type with name and commitSHA fields (mirrors GitHubRelease pattern)
  2. ✅ Simplified to single getAllTags() function returning GitHubTag[] (removed getAllTagsWithCommitSHA)
  3. ✅ Updated TerraformModule to store GitHubTag[] internally, mirroring how releases are handled
  4. ✅ Updated setTags() to match setReleases() pattern exactly (validates, extracts versions, sorts)
  5. ✅ Removed duplicate "Second pass" comment in setReleases()
  6. ✅ Updated getTagsForModule() and getTagsToDelete() to work with GitHubTag[]
  7. ✅ Created helper functions createMockTag() and createMockTags() for testing
  8. ✅ Updated createMockTerraformModule() to automatically convert string[] tags to GitHubTag[]
  9. ✅ All tests updated and passing (480 passing, 11 skipped requiring GITHUB_TOKEN)

The implementation now consistently uses GitHubTag type throughout, with commit SHAs populated directly from GitHub API's tag.commit.sha field.

Copilot finished work on behalf of virgofx October 2, 2025 06:26
Copy link
Member

@virgofx virgofx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Review comments. Additionally, let's add a new {{ ref_comment }} variable that adds the current tagVersion as a comment in standard notation # v2.2.3 ONLY if we use sha reference for the ref, otherwise, leave this as an empty string.

Copy link
Contributor Author

Copilot AI commented Oct 2, 2025

@copilot Review comments. Additionally, let's add a new {{ ref_comment }} variable that adds the current tagVersion as a comment in standard notation # v2.2.3 ONLY if we use sha reference for the r...

Done in 61c50e7. Added new ref_comment template variable that:

  • Shows # {tagVersion} (e.g., # v2.2.3) when using SHA mode
  • Returns empty string when using tag mode

This allows users to see the human-readable tag version as a comment when the ref contains a commit SHA.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • docs.github.com
    • Triggering command: curl -s REDACTED (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@virgofx virgofx self-requested a review October 2, 2025 06:42
Copilot finished work on behalf of virgofx October 2, 2025 06:43
Copy link
Member

@virgofx virgofx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot See inline comments.

Copy link
Contributor Author

Copilot AI commented Oct 2, 2025

@copilot See inline comments.

All inline comments addressed in 92bf0d5. Summary:

  • Tests simplified to use expectedTags with commitSHA directly
  • Switch statement logic cleaned up and simplified
  • ref_comment added to all documentation and templates
  • Variable ordering updated for consistency

@Copilot Copilot AI requested a review from virgofx October 2, 2025 07:01
Copilot finished work on behalf of virgofx October 2, 2025 07:01
@Copilot Copilot AI requested a review from virgofx October 2, 2025 07:12
Copilot finished work on behalf of virgofx October 2, 2025 07:12
Copilot finished work on behalf of virgofx October 2, 2025 07:13
Copy link
Member

@virgofx virgofx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot See inline changes. Additionally, can you update the pull request description based on the changes to not be checkbox-based. Instead, more summary-based (with bullet points as necessary).

Copy link
Contributor Author

Copilot AI commented Oct 2, 2025

@copilot See inline changes. Additionally, can you update the pull request description based on the changes to not be checkbox-based. Instead, more summary-based (with bullet points as necessary).

Updated in 7eeda49. Changed PR description from checkbox-based to summary-based with bullet points organized into clear sections (Overview, Problem Statement, Solution, Key Features, Implementation Details, etc.).

@Copilot Copilot AI requested a review from virgofx October 2, 2025 23:40
Copilot finished work on behalf of virgofx October 2, 2025 23:40
@virgofx virgofx force-pushed the copilot/fix-140f07b7-cb33-4fa9-b435-be76baf0a7ef branch 5 times, most recently from 54296bb to 8258de4 Compare October 6, 2025 04:07
@virgofx virgofx marked this pull request as ready for review October 6, 2025 04:11
@Copilot Copilot AI review requested due to automatic review settings October 6, 2025 04:11
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a new module-ref-mode configuration option that controls how Terraform module usage examples reference versions in generated wiki documentation. This addresses module removal scenarios where tags can be deleted, breaking references for users of outdated module versions.

Key Changes

  • Adds module-ref-mode parameter with "tag" (default) and "sha" modes for wiki documentation
  • Extracts Git authentication logic into reusable configureGitAuthentication() utility function
  • Updates tag handling to store commit SHAs alongside tag names using new GitHubTag type

Reviewed Changes

Copilot reviewed 24 out of 25 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/wiki.ts Updates wiki generation to support SHA mode with commit references and ref comments
src/utils/metadata.ts Adds module-ref-mode to action input metadata
src/utils/github.ts Extracts configureGitAuthentication function for reusable Git auth setup
src/utils/constants.ts Defines MODULE_REF_MODE constants and validation arrays
src/types/github.types.ts Adds GitHubTag interface with name and commitSHA fields
src/types/config.types.ts Adds ModuleRefMode type and moduleRefMode config property
src/terraform-module.ts Updates to use GitHubTag objects instead of string arrays for tags
src/tags.ts Modifies getAllTags to return GitHubTag objects with commit SHAs
src/releases.ts Updates release creation to store commit SHAs and use extracted auth function
src/parser.ts Updates parseTerraformModules to work with GitHubTag type
src/config.ts Adds validation for module-ref-mode parameter
package.json Updates dependency versions and prettier command
action.yml Adds module-ref-mode input parameter and updates usage template
__tests__/** Comprehensive test updates for new GitHubTag structure and SHA mode functionality
README.md Documents new module-ref-mode parameter and template variables
.github/workflows/ci.yml Updates CI configuration with new parameter

…cumentation

- Implemented `module-ref-mode` input to control how module versions are referenced in generated documentation (options: "tag" or "sha").
- Updated `configureGitAuthentication` function to handle GitHub token authentication for HTTPS operations.
- Enhanced tests for `configureGitAuthentication` to cover various scenarios including error handling and domain-specific configurations.
- Modified `generateWikiFiles` function to utilize the new `moduleRefMode` configuration, adjusting the reference format based on the selected mode.
- Refactored `TerraformModule` class to store tags as objects containing both name and commit SHA, allowing for better version management.
- Updated metadata and constants to include new module reference mode options and validation.
- Adjusted action YAML to include new input for `module-ref-mode` with appropriate descriptions.
@virgofx virgofx force-pushed the copilot/fix-140f07b7-cb33-4fa9-b435-be76baf0a7ef branch from 8258de4 to 2c8694c Compare October 6, 2025 04:14
Copy link

github-actions bot commented Oct 6, 2025

📋 Release Plan

Module Type Latest
Version
New
Version
Release
Details
tf-modules-kms patch v1.0.0 🆕 Initial Release
tf-modules-vpc-endpoint patch v1.0.0 🆕 Initial Release

📝 Changelog

tf-modules-kms-v1.0.0 (2025-10-06)

  • 🔀PR #283 - Add module-ref-mode config to support commit SHA references in wiki documentation

tf-modules-vpc-endpoint-v1.0.0 (2025-10-06)

  • 🔀PR #283 - Add module-ref-mode config to support commit SHA references in wiki documentation

Wiki Statusℹ️

✅ Enabled

Automated Tag/Release Cleanupℹ️

⏸️ Existing tags and releases will be preserved as the delete-legacy-tags flag is disabled.

Powered by:   techpivot/terraform-module-releaser

Copy link

sonarqubecloud bot commented Oct 6, 2025

@virgofx virgofx merged commit 941094f into main Oct 6, 2025
25 checks passed
@virgofx virgofx deleted the copilot/fix-140f07b7-cb33-4fa9-b435-be76baf0a7ef branch October 6, 2025 04:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Try to use digests not tags via Renovate, to deal with module removal issues

2 participants