Skip to content
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

feat: support terraform_version_file #454

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ steps:
terraform_version: "1.1.7"
```

A specific version of Terraform CLI can be installed using a version file:

```yaml
steps:
- uses: hashicorp/setup-terraform@v3
with:
terraform_version_file: ".tool-versions"
```

Credentials for HCP Terraform ([app.terraform.io](https://app.terraform.io/)) can be configured:

```yaml
Expand Down Expand Up @@ -251,10 +260,24 @@ The action supports the following inputs:
for available range specifications). Examples are: `"<1.2.0"`, `"~1.1.0"`, `"1.1.7"` (all three installing
the latest available `1.1` version). Prerelease versions can be specified and a range will stay within the
given tag such as `beta` or `rc`. If no version is given, it will default to `latest`.
- `terraform_version_file` - (optional) The path to a file containing terraform version. Supported file types are `.tool-versions` or anything else. See more details in [about version-file](#Terraform-version-file).
- `terraform_wrapper` - (optional) Whether to install a wrapper to wrap subsequent calls of
the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs
named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.

### Terraform version file

If the `terraform_version_file` input is specified, the action will extract the version from the file and install it.

Supported files names are `.tool-versions` or anything else.

Choose a reason for hiding this comment

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

We use .terraform-version which is a quasi-standard for Terraform: https://github.com/tfutils/tfenv?tab=readme-ov-file#terraform-version-file.

Copy link
Author

Choose a reason for hiding this comment

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

Do you mean replace or anything else. for .terraform-version?

I think keeping compatibility with https://github.com/asdf-vm/asdf by using .tool-versions is a good idea, for instance, some other GitHub actions use it:

Choose a reason for hiding this comment

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

The Java action also supports .java-version: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md.

I think it would be good to mention .terraform-version specifically because a lot of people are probably using it.

Copy link
Author

Choose a reason for hiding this comment

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

Sure, see 149638b (#454)

In `.tool-versions` file, terraform version should be preceded by the terraform keyword (e.g., `terraform 1.13.0`).
The `.tool-versions` file supports version specifications in accordance with Semantic Versioning ([semver](https://semver.org/)) and [Semver Ranges](https://www.npmjs.com/package/semver#ranges).
In other files, the version should be specified as explainied in the `terraform_version` input.

If both `terraform_version` and `terraform_version_file` inputs are provided, the `terraform_version` input will be used.

If the file contains multiple versions, only the first one will be recognized.

## Outputs

This action does not configure any outputs directly. However, when you set the `terraform_wrapper` input
Expand Down
4 changes: 3 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ inputs:
required: false
terraform_version:
description: 'The version of Terraform CLI to install. Instead of full version string you can also specify constraint string starting with "<" (for example `<1.13.0`) to install the latest version satisfying the constraint. A value of `latest` will install the latest version of Terraform CLI. Defaults to `latest`.'
default: 'latest'
required: false
terraform_version_file:
description: 'The path to the `.terraform-version` file. See examples of supported syntax in README file'
required: false
terraform_wrapper:
description: 'Whether or not to install a wrapper to wrap subsequent calls of the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.'
Expand Down
58 changes: 57 additions & 1 deletion lib/setup-terraform.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,70 @@ credentials "${credentialsHostname}" {
await fs.writeFile(credsFile, creds);
}

async function getVersionFromFileContent (versionFile) {
if (!versionFile) {
return;
}

let versionRegExp;
const versionFileName = path.basename(versionFile);
if (versionFileName === '.tool-versions') {
versionRegExp = /^(terraform\s+)(?<version>[^\s]+)$/m;
} else if (versionFileName) {
versionRegExp = /(?<version>[^\s]+)/;
} else {
return;
}

try {
const content = fs.readFileSync(versionFile).toString().trim();
let fileContent = '';
if (content.match(versionRegExp)?.groups?.version) {
fileContent = content.match(versionRegExp)?.groups?.version;
}
if (!fileContent) {
return;
}
core.debug(`Version from file '${fileContent}'`);
return fileContent;
} catch (error) {
if (error.code === 'ENOENT') {
return;
}
throw error;
}
}

// get the Terraform version from the action inputs
async function getTerraformVersion (versionInput, versionFile) {
const DEFAULT_VERSION = 'latest';

let version = versionInput;
if (!versionInput && !versionFile) {
core.info(`Set default value for version to ${DEFAULT_VERSION}`);
version = DEFAULT_VERSION;
}

if (!version && versionFile) {
version = await getVersionFromFileContent(versionFile);
if (!version) {
throw new Error(`No supported version was found in file ${versionFile}`);
}
}
return version;
}

async function run () {
try {
// Gather GitHub Actions inputs
const version = core.getInput('terraform_version');
const versionInput = core.getInput('terraform_version', { required: false });
const versionFile = core.getInput('terraform_version_file', { required: false });
const credentialsHostname = core.getInput('cli_config_credentials_hostname');
const credentialsToken = core.getInput('cli_config_credentials_token');
const wrapper = core.getInput('terraform_wrapper') === 'true';

const version = await getTerraformVersion(versionInput, versionFile);

// Gather OS details
const osPlatform = os.platform();
const osArch = os.arch();
Expand Down
Loading