Skip to content

183 semver pattern without v prefix #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5d7b3ec
feat: add centralized action metadata system with proper array parsing
virgofx Jun 13, 2025
292544a
refactor: update config system to use centralized action metadata
virgofx Jun 13, 2025
9e0210a
test: improve test infrastructure and input helpers
virgofx Jun 13, 2025
664a722
test: add comprehensive config validation test coverage
virgofx Jun 13, 2025
78ef888
fix: resolve context test environment variable issues
virgofx Jun 13, 2025
763b1e5
fix: correct import paths and type inconsistencies
virgofx Jun 13, 2025
de65653
chore: update dependencies and action.yml defaults
virgofx Jun 13, 2025
58e7ce4
chore: update package dependencies to latest versions
virgofx Jun 16, 2025
b60f5ab
fix: remove unnecessary SSH agent forwarding and update prettier feature
virgofx Jun 16, 2025
55f859c
fix: update super-linter action to specific version for consistency
virgofx Jun 16, 2025
960a027
fix: update create-pull-request action to specific version for stability
virgofx Jun 16, 2025
ccee33c
fix: update SonarQube scan action to specific commit SHA for stability
virgofx Jun 16, 2025
a25b383
fix: update package dependencies to latest versions for improved stab…
virgofx Jun 19, 2025
3edc48d
feat: support optional v prefix with directory separator config
virgofx Jun 19, 2025
d10851d
fix: update rollup packages to version 4.44.0 for improved compatibility
virgofx Jun 19, 2025
e9acd72
feat: enhance tag generation configuration with detailed descriptions…
virgofx Jun 19, 2025
6f9dd52
fix: remove eslint directive for throwing literals in metadata tests
virgofx Aug 19, 2025
2f035a0
chore: update dependencies
virgofx Aug 19, 2025
b50b1e0
chore: update dependencies and improve variable naming
virgofx Aug 19, 2025
eb44238
fix: update @types/node to version 22.17.2 for improved compatibility
virgofx Aug 19, 2025
2bde36f
fix: update GitHub token reference for CI testing in workflow
virgofx Aug 19, 2025
283379b
refactor: simplify ACTION_INPUTS metadata definitions using factory f…
virgofx Aug 19, 2025
137179f
test: enhance ACTION_INPUTS tests for metadata structure and type safety
virgofx Aug 19, 2025
f13f153
fix: formatting
virgofx Aug 19, 2025
1b701e6
test: add tests for VALID_TAG_DIRECTORY_SEPARATORS, VERSION_TAG_REGEX…
virgofx Aug 19, 2025
9ab9723
refactor: remove redundant SonarQube job steps from workflow
virgofx Aug 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"markdown.extension.list.indentationSize": "adaptive",
"markdown.extension.italic.indicator": "_",
"markdown.extension.orderedList.marker": "one",
"remote.SSH.enableAgentForwarding": true,
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
Expand All @@ -52,7 +51,6 @@
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
},
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers-contrib/features/prettier:1": {}
"ghcr.io/devcontainers-community/npm-features/prettier": {}
}
}
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ jobs:
module-change-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**,examples/**
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
use-ssh-source-format: true
tag-directory-separator: "-"
use-version-prefix: false

- name: Test Action Outputs
id: test-outputs
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:

- name: Lint Codebase
id: super-linter
uses: super-linter/super-linter/slim@v7
uses: super-linter/super-linter@12150456a73e248bdc94d0794898f94e23127c88 # v7.4.0
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ jobs:
}

- name: Create Branch and Pull Request
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ steps.app-token.outputs.token }}
base: main
Expand Down
10 changes: 6 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ on:
types: [opened, synchronize, reopened]

jobs:
tests:
Tests:
runs-on: ubuntu-latest
name: Test
name: TypeScript Tests
permissions:
contents: read
steps:
Expand All @@ -33,9 +33,11 @@ jobs:
- name: Run Tests Typescript
run: npm run test
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO_CI_TESTING }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Note: SonarQube requires the results from tests to get the coverage report
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v5
uses: SonarSource/sonarqube-scan-action@2500896589ef8f7247069a56136f8dc177c27ccf # v5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ configuring the following optional input parameters as needed.
| `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/**` |
| `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/**` |
| `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` |
| `tag-directory-separator` | Character used to separate directory path components in Git tags. Supports `/`, `-`, `_`, or `.` | `/` |
| `use-version-prefix` | Whether to include the 'v' prefix on version tags (e.g., v1.2.3 vs 1.2.3) | `true` |

### Understanding the filtering options

Expand Down
32 changes: 16 additions & 16 deletions __mocks__/@actions/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ type MockedFunction<TFunc> = TFunc extends (...args: infer TArgs) => infer TRetu
* Writes a debug message to the user log.
* @param message - The debug message to log.
*/
export const debug: MockedFunction<(message: string) => void> = vi.fn((message: string): void => {});
export const debug: MockedFunction<(message: string) => void> = vi.fn((_message: string): void => {});

/**
* Writes an informational message to the log.
* @param message - The info message to log.
*/
export const info: MockedFunction<(message: string) => void> = vi.fn((message: string): void => {});
export const info: MockedFunction<(message: string) => void> = vi.fn((_message: string): void => {});

/**
* Adds a warning issue with optional annotation properties.
* @param message - The warning message or error.
* @param properties - Optional properties to add to the annotation.
*/
export const warning: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
(message: string | Error, properties?: AnnotationProperties): void => {},
(_message: string | Error, _properties?: AnnotationProperties): void => {},
);

/**
Expand All @@ -37,7 +37,7 @@ export const warning: MockedFunction<(message: string | Error, properties?: Anno
* @param properties - Optional properties to add to the annotation.
*/
export const notice: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
(message: string | Error, properties?: AnnotationProperties): void => {},
(_message: string | Error, _properties?: AnnotationProperties): void => {},
);

/**
Expand All @@ -46,7 +46,7 @@ export const notice: MockedFunction<(message: string | Error, properties?: Annot
* @param properties - Optional properties to add to the annotation.
*/
export const error: MockedFunction<(message: string | Error, properties?: AnnotationProperties) => void> = vi.fn(
(message: string | Error, properties?: AnnotationProperties): void => {},
(_message: string | Error, _properties?: AnnotationProperties): void => {},
);

/**
Expand All @@ -55,13 +55,13 @@ export const error: MockedFunction<(message: string | Error, properties?: Annota
* @param message - The error message or object.
* @throws An error with the specified message.
*/
export const setFailed: MockedFunction<(message: string | Error) => void> = vi.fn((message: string | Error) => {});
export const setFailed: MockedFunction<(message: string | Error) => void> = vi.fn((_message: string | Error) => {});

/**
* Begins a new output group. Output until the next `endGroup` will be foldable in this group.
* @param name - The name of the output group.
*/
export const startGroup: MockedFunction<(name: string) => void> = vi.fn((name: string): void => {});
export const startGroup: MockedFunction<(name: string) => void> = vi.fn((_name: string): void => {});

/**
* Ends the current output group.
Expand Down Expand Up @@ -109,36 +109,36 @@ export const getMultilineInput: MockedFunction<(name: string, options?: InputOpt
* Masks a value in the log. When the masked value appears in the log, it is replaced with asterisks.
* @param secret - Value to mask
*/
export const setSecret: MockedFunction<(secret: string) => void> = vi.fn((secret: string): void => {});
export const setSecret: MockedFunction<(secret: string) => void> = vi.fn((_secret: string): void => {});

/**
* Prepends the given path to the PATH environment variable.
* @param inputPath - Path to prepend
*/
export const addPath: MockedFunction<(inputPath: string) => void> = vi.fn((inputPath: string): void => {});
export const addPath: MockedFunction<(inputPath: string) => void> = vi.fn((_inputPath: string): void => {});

/**
* Sets env variable for this action and future actions in the job.
* @param name - Name of the variable to set
* @param val - Value of the variable
*/
export const exportVariable: MockedFunction<(name: string, val: string) => void> = vi.fn(
(name: string, val: string): void => {},
(_name: string, _val: string): void => {},
);

/**
* Enables or disables the echoing of commands into stdout for the rest of the step.
* @param enabled - True to enable echoing, false to disable
*/
export const setCommandEcho: MockedFunction<(enabled: boolean) => void> = vi.fn((enabled: boolean): void => {});
export const setCommandEcho: MockedFunction<(enabled: boolean) => void> = vi.fn((_enabled: boolean): void => {});

/**
* Begin an output group.
* @param name - Name of the output group
* @param fn - Function to execute within the output group
*/
export const group: MockedFunction<(name: string, fn: () => Promise<void>) => Promise<void>> = vi.fn(
async (name: string, fn: () => Promise<void>): Promise<void> => {
async (_name: string, fn: () => Promise<void>): Promise<void> => {
await fn();
},
);
Expand All @@ -150,15 +150,15 @@ export const group: MockedFunction<(name: string, fn: () => Promise<void>) => Pr
* @param value - Value to store. Non-string values will be converted to a string via JSON.stringify
*/
export const saveState: MockedFunction<(name: string, value: string) => void> = vi.fn(
(name: string, value: string): void => {},
(_name: string, _value: string): void => {},
);

/**
* Gets the value of an state set by this action's main execution.
* @param name - Name of the state to get
* @returns string
*/
export const getState: MockedFunction<(name: string) => string> = vi.fn((name: string): string => '');
export const getState: MockedFunction<(name: string) => string> = vi.fn((_name: string): string => '');

/**
* Gets whether Actions Step Debug is on or not
Expand All @@ -172,7 +172,7 @@ export const isDebug: MockedFunction<() => boolean> = vi.fn((): boolean => false
* @returns string
*/
export const getIDToken: MockedFunction<(audience?: string) => Promise<string>> = vi.fn(
async (audience?: string): Promise<string> => '',
async (_audience?: string): Promise<string> => '',
);

/**
Expand All @@ -181,7 +181,7 @@ export const getIDToken: MockedFunction<(audience?: string) => Promise<string>>
* @param value - Value to store. Non-string values will be converted to a string via JSON.stringify
*/
export const setOutput: MockedFunction<(name: string, value: string) => void> = vi.fn(
(name: string, value: string): void => {},
(_name: string, _value: string): void => {},
);

// Re-export types
Expand Down
55 changes: 19 additions & 36 deletions __mocks__/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { setupTestInputs } from '@/tests/helpers/inputs';
import type { Config } from '@/types';
import type { ActionInputMetadata } from '@/types';
import { ACTION_INPUTS, createConfigFromInputs } from '@/utils/metadata';

/**
* Configuration interface with added utility methods
Expand All @@ -9,44 +12,24 @@ interface ConfigWithMethods extends Config {
}

/**
* Default configuration object.
* Load default configuration from action.yml.
*/
const defaultConfig: Config = {
majorKeywords: ['BREAKING CHANGE', '!', 'MAJOR CHANGE'],
minorKeywords: ['feat', 'feature'],
patchKeywords: ['fix', 'chore'],
defaultFirstTag: 'v1.0.0',
terraformDocsVersion: 'v0.20.0',
deleteLegacyTags: false,
disableWiki: false,
wikiSidebarChangelogMax: 10,
disableBranding: false,
modulePathIgnore: ['tf-modules/kms/examples/complete'],
moduleChangeExcludePatterns: ['.gitignore', '*.md'],
moduleAssetExcludePatterns: ['tests/**', 'examples/**'],
githubToken: 'ghp_test_token_2c6912E7710c838347Ae178B4',
useSSHSourceFormat: false,
const createDefaultConfig = (): Config => {
setupTestInputs();
return createConfigFromInputs();
};

/**
* Valid configuration keys.
* Default configuration object loaded from action.yml.
*/
const validConfigKeys = [
'majorKeywords',
'minorKeywords',
'patchKeywords',
'defaultFirstTag',
'terraformDocsVersion',
'deleteLegacyTags',
'disableWiki',
'wikiSidebarChangelogMax',
'disableBranding',
'modulePathIgnore',
'moduleChangeExcludePatterns',
'moduleAssetExcludePatterns',
'githubToken',
'useSSHSourceFormat',
] as const;
const defaultConfig: Config = createDefaultConfig();

/**
* Valid configuration keys derived from ACTION_INPUTS.
*/
const validConfigKeys = (Object.values(ACTION_INPUTS) as ActionInputMetadata[]).map(
(metadata) => metadata.configKey,
) as Array<keyof Config>;

type ValidConfigKey = (typeof validConfigKeys)[number];

Expand All @@ -57,7 +40,7 @@ let currentConfig: Config = { ...defaultConfig };
* Config proxy handler.
*/
const configProxyHandler: ProxyHandler<ConfigWithMethods> = {
set(target: ConfigWithMethods, key: string, value: unknown): boolean {
set(_target: ConfigWithMethods, key: string, value: unknown): boolean {
if (!validConfigKeys.includes(key as ValidConfigKey)) {
throw new Error(`Invalid config key: ${key}`);
}
Expand All @@ -66,15 +49,15 @@ const configProxyHandler: ProxyHandler<ConfigWithMethods> = {
const expectedValue = defaultConfig[typedKey];

if ((Array.isArray(expectedValue) && Array.isArray(value)) || typeof expectedValue === typeof value) {
// @ts-ignore - we know that the key is valid and that the value is correct
// @ts-expect-error - we know that the key is valid and that the value is correct
currentConfig[typedKey] = value as typeof expectedValue;
return true;
}

throw new TypeError(`Invalid value type for config key: ${key}`);
},

get(target: ConfigWithMethods, prop: string | symbol): unknown {
get(_target: ConfigWithMethods, prop: string | symbol): unknown {
if (typeof prop === 'string') {
if (prop === 'set') {
return (overrides: Partial<Config> = {}) => {
Expand Down
6 changes: 3 additions & 3 deletions __mocks__/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ let currentContext: Context = { ...defaultContext };
* Context proxy handler
*/
const contextProxyHandler: ProxyHandler<ContextWithMethods> = {
set(target: ContextWithMethods, key: string, value: unknown): boolean {
set(_target: ContextWithMethods, key: string, value: unknown): boolean {
if (!validContextKeys.includes(key as ValidContextKey)) {
throw new Error(`Invalid context key: ${key}`);
}
Expand All @@ -68,15 +68,15 @@ const contextProxyHandler: ProxyHandler<ContextWithMethods> = {
const expectedValue = defaultContext[typedKey];

if (typeof expectedValue === typeof value || (typedKey === 'octokit' && typeof value === 'object')) {
// @ts-ignore - we know the key is valid and value type is correct
// @ts-expect-error - we know the key is valid and value type is correct
currentContext[typedKey] = value;
return true;
}

throw new TypeError(`Invalid value type for context key: ${key}`);
},

get(target: ContextWithMethods, prop: string | symbol): unknown {
get(_target: ContextWithMethods, prop: string | symbol): unknown {
if (typeof prop === 'string') {
if (prop === 'set') {
return (overrides: Partial<Context> = {}) => {
Expand Down
6 changes: 5 additions & 1 deletion __tests__/_setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setupTestInputs } from '@/tests/helpers/inputs';
import { afterEach, beforeEach, vi } from 'vitest';

// Mocked node modules (./__mocks__/*)
Expand All @@ -20,11 +21,14 @@ const defaultEnvironmentVariables = {
};

beforeEach(() => {
// Initialize environment
// Initialize GitHub mock pull request environment
for (const [key, value] of Object.entries(defaultEnvironmentVariables)) {
vi.stubEnv(key, value);
}

// Set up action input defaults for testing
setupTestInputs();

// Clear all mocked functions usage data and state
vi.clearAllMocks();
});
Expand Down
Loading