Skip to content

Commit

Permalink
feat: add useSSHSourceFormat option to configure source URL format in…
Browse files Browse the repository at this point in the history
… Wiki documentation
  • Loading branch information
virgofx committed Feb 7, 2025
1 parent 46b354c commit e0d88c8
Show file tree
Hide file tree
Showing 14 changed files with 110 additions and 14 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ jobs:
delete-legacy-tags: false # Note: We don't want to delete tags in this repository
module-change-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
use-ssh-source-format: true
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_REPO_CI_TESTING }}

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@v4
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@v4
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 @@ -182,6 +182,7 @@ configuring the following optional input parameters as needed.
| `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` |
| `module-change-exclude-patterns` | A comma-separated list of file patterns to exclude from triggering version changes in Terraform modules. Patterns follow glob syntax (e.g., `.gitignore,_.md`) and are relative to each Terraform module directory. Files matching these patterns will not affect version changes. **WARNING**: Avoid excluding '`_.tf`' files, as they are essential for module detection and versioning processes. | `.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://git@github.com/owner/repo.git`) instead of HTTPS format (`git::https://github.com/owner/repo.git`) | `false` |

### Example Usage with Inputs

Expand Down Expand Up @@ -217,6 +218,7 @@ jobs:
wiki-sidebar-changelog-max: 10
module-change-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
module-asset-exclude-patterns: .gitignore,*.md,*.tftest.hcl,tests/**
use-ssh-source-format: false
```

## Inspiration
Expand Down
2 changes: 2 additions & 0 deletions __mocks__/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const defaultConfig: Config = {
moduleChangeExcludePatterns: ['.gitignore', '*.md'],
moduleAssetExcludePatterns: ['tests/**', 'examples/**'],
githubToken: 'ghp_test_token_2c6912E7710c838347Ae178B4',
useSSHSourceFormat: false,
};

/**
Expand All @@ -42,6 +43,7 @@ const validConfigKeys = [
'moduleChangeExcludePatterns',
'moduleAssetExcludePatterns',
'githubToken',
'useSSHSourceFormat',
] as const;

type ValidConfigKey = (typeof validConfigKeys)[number];
Expand Down
1 change: 1 addition & 0 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ describe('config', () => {
expect(config.githubToken).toBe('ghp_test_token_2c6912E7710c838347Ae178B4');
expect(config.moduleChangeExcludePatterns).toEqual(['.gitignore', '*.md']);
expect(config.moduleAssetExcludePatterns).toEqual(['tests/**', 'examples/**']);
expect(config.useSSHSourceFormat).toBe(false);
expect(startGroup).toHaveBeenCalledWith('Initializing Config');
expect(startGroup).toHaveBeenCalledTimes(1);
expect(endGroup).toHaveBeenCalledTimes(1);
Expand Down
3 changes: 2 additions & 1 deletion __tests__/helpers/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ export const defaultInputs = {
'module-change-exclude-patterns': '.gitignore,*.md',
'module-asset-exclude-patterns': 'tests/**,examples/**',
github_token: 'ghp_test_token_2c6912E7710c838347Ae178B4',
'use-ssh-source-format': 'false',
};
export const requiredInputs = Object.keys(defaultInputs);
export const booleanInputs = ['delete-legacy-tags', 'disable-wiki', 'disable-branding'];
export const booleanInputs = ['delete-legacy-tags', 'disable-wiki', 'disable-branding', 'use-ssh-source-format'];
export const booleanConfigKeys: BooleanConfigKeys[] = ['deleteLegacyTags', 'disableWiki', 'disableBranding'];

/**
Expand Down
18 changes: 15 additions & 3 deletions __tests__/terraform-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { context } from '@/mocks/context';
import { ensureTerraformDocsConfigDoesNotExist, generateTerraformDocs, installTerraformDocs } from '@/terraform-docs';
import type { TerraformModule } from '@/types';
import { info } from '@actions/core';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import which from 'which';

const execFilePromisified = promisify(execFile);
Expand Down Expand Up @@ -50,7 +50,6 @@ describe('terraform-docs', async () => {
afterEach(() => {
Object.defineProperty(process, 'platform', { value: realPlatform });
Object.defineProperty(process, 'arch', { value: realArch });
vi.resetAllMocks();
});

describe('install terraform-docs (linux, darwin, freebsd)', () => {
Expand Down Expand Up @@ -184,6 +183,10 @@ describe('terraform-docs', async () => {

expect(() => installTerraformDocs(terraformDocsVersion)).toThrow('not found: invalid-non-existent-binary');
});

afterAll(() => {
mockWhichSync.mockRestore();
});
});

describe('terraform-docs version validation', () => {
Expand Down Expand Up @@ -219,7 +222,7 @@ describe('terraform-docs', async () => {
join('C:\\Windows\\System32', 'terraform-docs.exe'),
];

beforeEach(async () => {
beforeAll(async () => {
// Get real implementations
const realChildProcess = (await vi.importActual('node:child_process')) as typeof import('node:child_process');
const realFs = (await vi.importActual('node:fs')) as typeof import('node:fs');
Expand All @@ -232,6 +235,14 @@ describe('terraform-docs', async () => {
mockWhichSync.mockImplementation(realWhich.sync);
});

afterAll(() => {
// Restore original mock implementations
mockExecFileSync.mockRestore();
fsExistsSyncMock.mockRestore();
mockFsUnlinkSync.mockRestore();
mockWhichSync.mockRestore();
});

afterEach(() => {
// Cleanup downloaded/installed files
for (const file of cleanupFiles) {
Expand All @@ -243,6 +254,7 @@ describe('terraform-docs', async () => {
}

// Restore original mock implementations (handled via global resetAllMocks())

});

it(`should install terraform-docs on the real system ${process.arch}/${process.platform}`, () => {
Expand Down
47 changes: 47 additions & 0 deletions __tests__/wiki.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,51 @@ describe('wiki', async () => {
expect(commitCall?.[1]).toEqual(['commit', '-m', 'PR #456 - Complex PR title\n\nLine 1\nLine 2\nLine 3']);
});
});

describe('formatModuleSource()', () => {
beforeEach(() => {
context.set({
repo: { owner: 'techpivot', repo: 'terraform-module-releaser' },
repoUrl: 'https://github.com/techpivot/terraform-module-releaser',
});
});

it('should format source URL as HTTPS when useSSHSourceFormat is false', async () => {
config.set({ useSSHSourceFormat: false });
const files = await generateWikiFiles(terraformModules);

// Read each generated .md file and verify it contains HTTPS format
for (const file of files) {
if (file.endsWith('.md')) {
const content = readFileSync(file, 'utf8');
if (content.includes('source =')) {
expect(content).toContain('source = "git::https://github.com/techpivot/terraform-module-releaser.git?ref=');
expect(content).not.toContain(
'source = "git::ssh://git@github.com/techpivot/terraform-module-releaser.git?ref=',
);
}
}
}
});

it('should format source URL as SSH when useSSHSourceFormat is true', async () => {
config.set({ useSSHSourceFormat: true });
const files = await generateWikiFiles(terraformModules);

// Read each generated .md file and verify it contains SSH format
for (const file of files) {
if (file.endsWith('.md')) {
const content = readFileSync(file, 'utf8');
if (content.includes('source =')) {
expect(content).toContain(
'source = "git::ssh://git@github.com/techpivot/terraform-module-releaser.git?ref=',
);
expect(content).not.toContain(
'source = "git::https://github.com/techpivot/terraform-module-releaser.git?ref=',
);
}
}
}
});
});
});
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ inputs:
The minimatch syntax is used for pattern matching. Files matching these patterns will be excluded from the bundled output.
required: true
default: ".gitignore,*.md,*.tftest.hcl,tests/**"
use-ssh-source-format:
description: If enabled, all links to source code in generated Wiki documentation will use SSH format instead of HTTPS format
required: true
default: "false"
github_token:
description: |
Required for retrieving pull request metadata, tags, releases, updating PR comments, wiki, and creating tags/releases.
Expand Down
8 changes: 1 addition & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@
"bugs": {
"url": "https://github.com/techpivot/terraform-module-releaser/issues"
},
"keywords": [
"terraform",
"module",
"releaser",
"github-action",
"monorepo"
],
"keywords": ["terraform", "module", "releaser", "github-action", "monorepo"],
"license": "MIT",
"exports": {
".": "./dist/index.js"
Expand Down
1 change: 1 addition & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
sonar.organization=techpivot
sonar.projectKey=terraform-module-releaser
sonar.projectName=Terraform Module Releaser
sonar.projectDescription=A GitHub Action for managing Terraform modules in GitHub monorepos, automating versioning, releases, and documentation.

sonar.sourceEncoding=UTF-8

Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function initializeConfig(): Config {
githubToken: getInput('github_token', { required: true }),
moduleChangeExcludePatterns: getArrayInput('module-change-exclude-patterns'),
moduleAssetExcludePatterns: getArrayInput('module-asset-exclude-patterns'),
useSSHSourceFormat: getBooleanInput('use-ssh-source-format', { required: true }),
};

// Validate that *.tf is not in excludePatterns
Expand Down
12 changes: 12 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@ export interface Config {
* tests and other non-functional files as needed.
*/
moduleAssetExcludePatterns: string[];

/**
* If true, the wiki will use the SSH format for the source URL of the repository.
* This changes the format of the source URL in the generated wiki documentation to use the SSH format.
*
* Example:
* - SSH format: git::ssh://git@github.com/techpivot/terraform-module-releaser.git
* - HTTPS format: git::https://github.com/techpivot/terraform-module-releaser.git
*
* When set to true, the SSH standard format (non scp variation) will be used. Otherwise, the HTTPS format will be used.
*/
useSSHSourceFormat: boolean;
}

/**
Expand Down
20 changes: 19 additions & 1 deletion src/wiki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@ export function getWikiLink(moduleName: string, relative = true): string {
return `${baseUrl}/wiki/${getWikiSlug(moduleName)}`;
}

/**
* Formats the module source URL based on configuration settings.
*
* @param repoUrl - The repository URL
* @param useSSH - Whether to use SSH format
* @returns The formatted source URL for the module
*/
function formatModuleSource(repoUrl: string, useSSH: boolean): string {
if (useSSH) {
// Convert HTTPS URL to SSH format
// From: https://github.com/owner/repo
// To: ssh://git@github.com/owner/repo
return `ssh://${repoUrl.replace(/^https:\/\/github\.com/, 'git@github.com')}.git`;
}
return `${repoUrl}.git`;
}

/**
* Generates the wiki file associated with the specified Terraform module.
* Ensures that the directory structure is created if it doesn't exist and handles overwriting
Expand All @@ -209,12 +226,13 @@ async function generateWikiModule(terraformModule: TerraformModule): Promise<str
// Generate a module changelog
const changelog = getModuleReleaseChangelog(terraformModule);
const tfDocs = await generateTerraformDocs(terraformModule);
const moduleSource = formatModuleSource(context.repoUrl, config.useSSHSourceFormat);
const wikiContent = [
'# Usage\n',
'To use this module in your Terraform, refer to the below module example:\n',
'```hcl',
`module "${moduleName.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase()}" {`,
` source = "git::${context.repoUrl}.git?ref=${latestTag}"`,
` source = "git::${moduleSource}?ref=${latestTag}"`,
'\n # See inputs below for additional required parameters',
'}',
'```',
Expand Down

0 comments on commit e0d88c8

Please sign in to comment.