Compare commits

..

No commits in common. "main" and "v1.0.2" have entirely different histories.
main ... v1.0.2

18 changed files with 5738 additions and 56695 deletions

View file

@ -1,19 +1,19 @@
name: "Continuous Integration"
name: 'Continuous Integration'
on:
push:
branches:
- main
- main
pull_request:
jobs:
check-dist:
name: Check dist/ directory
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@2826fb8353263a138210fc017301ce5767a9c0d4
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@967035ce963867fb956a309c9b67512314bc7c1f
with:
node-version: "20.19.1"
node-version: "20.x"
test:
name: Test
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@2826fb8353263a138210fc017301ce5767a9c0d4
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@967035ce963867fb956a309c9b67512314bc7c1f
with:
node-version: "20.19.1"
node-version: "20.x"

View file

@ -1 +0,0 @@
latest

View file

@ -14,32 +14,13 @@ env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
tofu-version-files:
name: 'OpenTofu Version Files'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
tofu-version-files: ['./.github/workflows/data/local/.opentofu-version']
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup OpenTofu - ${{ matrix['tofu-version-files'] }}
uses: ./
with:
tofu_version_file: ${{ matrix['tofu-version-files'] }}
tofu_wrapper: false
- name: Validate that OpenTofu was installed
run: tofu version | grep 'OpenTofu v'
tofu-versions:
name: 'OpenTofu Versions'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
tofu-versions: [1.6.0, latest]
tofu-versions: [1.6.0-alpha1, latest]
tofu-wrapper: [true, false]
steps:
- name: Checkout

View file

@ -4,9 +4,4 @@
# We currently do not have any specific code owners
# In the future, we will have a Github team of global code owners of the entire package
# Later on, we will start splitting up the responsibilities, and packages will be assigned more specific code owners
* @opentofu/maintainers
# The last matching pattern takes the most precedence for CODEOWNERS. CODEOWNERS does not have fine-grained control so we will
# just match whole changes for these specific files, but @diofeher is responsible for taking care of the Dependabot updates
# in this repository.
package*.json @diofeher
# * @opentofu-code-owners

10
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,10 @@
# Code of Conduct
We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
<!-- TODO: Decide who will handle Code of Conduct reports and replace [INSERT EMAIL ADDRESS]
with an email address in the paragraph below. We recommend using a mailing list to handle reports.
If your project isn't prepared to handle reports, remove the project email address and just have
reporters send to conduct@cncf.io.
-->
Please contact contact@opentf.org in order to report violations of the Code of Conduct.

View file

@ -1,12 +1,18 @@
# GitHub Action for setting up OpenTofu
# setup-opentofu
> [!NOTE]
> This is a community-maintained repository. The OpenTofu team does not fix non-critical bugs or add features, but is happy to review community pull requests.
The `opentofu/setup-opentofu` action sets up OpenTofu CLI in your GitHub Actions workflow by:
> [!TIP]
> Having trouble with exit codes or the output format? Try setting the `tofu_wrapper` setting to `false`.
- Downloading the latest version of OpenTofu CLI and adding it to the `PATH`.
- Configuring the [CLI configuration file](https://opentofu.org/docs/cli/config/config-file/) with a Terraform Cloud/Enterprise hostname and API token.
- Installing a wrapper script to wrap subsequent calls of the `tofu` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. (This can be optionally skipped if subsequent steps in the same job do not need to access the results of
OpenTofu commands.)
The `opentofu/setup-opentofu` action sets up OpenTofu CLI in GitHub Actions.
After you've used the action, subsequent steps in the same job can run arbitrary OpenTofu commands using [the GitHub Actions `run` syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun). This allows most OpenTofu commands to work exactly
like they do on your local command line.
## Experimental Status
By using the software in this repository (the "Software"), you acknowledge that: (1) the Software is still in development, may change, and has not been released as a commercial product by OpenTofu; (2) the Software is provided on an "as-is" basis, and may include bugs, errors, or other issues; (3) the Software is NOT INTENDED FOR PRODUCTION USE, use of the Software may result in unexpected results, loss of data, or other unexpected results, and OpenTofu disclaims any and all liability resulting from use of the Software.
## Usage
@ -28,17 +34,6 @@ steps:
tofu_version: 1.6.0
```
You can also specify the version in a file (e.g., `.opentofu-version`):
```yaml
steps:
- uses: opentofu/setup-opentofu@v1
with:
tofu_version_file: .opentofu-version
```
Supported version syntax is the same as for the `tofu_version` input. If both `tofu_version` and `tofu_version_file` are provided, the version number in the file takes precedence.
Credentials for Terraform Cloud ([app.terraform.io](https://app.terraform.io/)) can be configured:
```yaml
@ -259,8 +254,6 @@ The action supports the following inputs:
for available range specifications). Examples are: `<1.6.0-beta`, `~1.6.0-alpha`, `1.6.0-alpha2` (all three installing
the latest available `1.6.0-alpha2` 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`.
- `tofu_version_file` - (optional) Path to a file containing the OpenTofu version to install. Supported version syntax
is the same as for the `tofu_version` input. Takes precedence over `tofu_version` if both are provided.
- `tofu_wrapper` - (optional) Whether to install a wrapper to wrap subsequent calls of
the `tofu` binary and expose its STDOUT, STDERR, and exit code as outputs
named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.
@ -279,3 +272,6 @@ to `true`, the following outputs are available for subsequent steps that call th
[Mozilla Public License v2.0](LICENSE)
## Code of Conduct
[Code of Conduct](CODE_OF_CONDUCT.md)

View file

@ -13,9 +13,6 @@ inputs:
description: 'The version of OpenTofu CLI to install. If no version is given, it will default to `latest`.'
default: 'latest'
required: false
tofu_version_file:
description: 'Path to a file containing the OpenTofu version to install. Takes precedence over `tofu_version` if both are provided.'
required: false
tofu_wrapper:
description: 'Whether or not to install a wrapper to wrap subsequent calls of the `tofu` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. Defaults to `true`.'
default: 'true'

31656
dist/index.js vendored

File diff suppressed because one or more lines are too long

26810
dist/index1.js vendored

File diff suppressed because one or more lines are too long

View file

@ -4,16 +4,16 @@
*/
class Build {
constructor (version, name) {
constructor (name, url) {
this.name = name;
this.url = 'https://github.com/opentofu/opentofu/releases/download/v' + version + '/' + name;
this.url = url;
}
}
class Release {
constructor (releaseMeta) {
this.version = releaseMeta.id.replace('v', '');
this.builds = releaseMeta.files.map(asset => new Build(this.version, asset));
this.version = releaseMeta.tag_name.replace('v', '');
this.builds = releaseMeta.assets.map(asset => new Build(asset.name, asset.browser_download_url));
}
getBuild (platform, arch) {
@ -28,38 +28,34 @@ class Release {
* @return {Array<Release>} Releases.
*/
async function fetchReleases (githubToken) {
const hc = require('@actions/http-client');
const userAgent = 'opentofu/setup-opentofu';
const http = new hc.HttpClient(userAgent);
const url = 'https://get.opentofu.org/tofu/api.json';
const url = 'https://api.github.com/repos/opentofu/opentofu/releases';
const headers = {
Accept: 'application/json'
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
};
const resp = await http.get(url, headers);
if (resp.message.statusCode !== hc.HttpCodes.OK) {
throw new Error('failed fetching releases (' + resp.message.statusCode + ')');
if (githubToken) {
headers.Authorization = `Bearer ${githubToken}`;
}
const body = await resp.readBody();
const releasesMeta = JSON.parse(body);
const resp = await fetch(url, {
headers
});
/**
* @type {Array}
*/
const versions = releasesMeta.versions;
if (!resp.ok) {
throw new Error('failed fetching releases (' + resp.status + ')');
}
return versions.map(releaseMeta => new Release(releaseMeta));
const releasesMeta = await resp.json();
return releasesMeta.map(releaseMeta => new Release(releaseMeta));
}
const semver = require('semver');
async function findLatestVersion (versions) {
return versions.filter((v) => semver.prerelease(v) === null).sort((a, b) => semver.rcompare(a, b))[0];
return versions.sort((a, b) => semver.rcompare(a, b))[0];
}
async function findLatestVersionInRange (versions, range) {

View file

@ -48,7 +48,7 @@ async function downloadAndExtractCLI (url) {
if (os.platform().startsWith('win')) {
core.debug(`OpenTofu CLI Download Path is ${pathToCLIZip}`);
const fixedPathToCLIZip = `${pathToCLIZip}.zip`;
await io.mv(pathToCLIZip, fixedPathToCLIZip);
io.mv(pathToCLIZip, fixedPathToCLIZip);
core.debug(`Moved download to ${fixedPathToCLIZip}`);
pathToCLI = await tc.extractZip(fixedPathToCLIZip);
} else {
@ -105,7 +105,7 @@ async function addCredentials (credentialsHostname, credentialsToken, osPlat) {
credentials "${credentialsHostname}" {
token = "${credentialsToken}"
}`.trim();
// eslint-enable
// eslint-enable
// default to OS-specific path
let credsFile = osPlat === 'win32'
@ -128,8 +128,7 @@ credentials "${credentialsHostname}" {
async function run () {
try {
// Gather GitHub Actions inputs
let version = core.getInput('tofu_version');
const versionFile = core.getInput('tofu_version_file');
const version = core.getInput('tofu_version');
const credentialsHostname = core.getInput('cli_config_credentials_hostname');
const credentialsToken = core.getInput('cli_config_credentials_token');
const wrapper = core.getInput('tofu_wrapper') === 'true';
@ -140,27 +139,6 @@ async function run () {
githubToken = process.env.GITHUB_TOKEN;
}
// If tofu_version_file is provided, read the version from the file
if (versionFile) {
try {
core.debug(`Reading OpenTofu version from file: ${versionFile}`);
const fileVersion = await fs.readFile(versionFile, 'utf8');
const trimmedVersion = fileVersion.trim();
if (trimmedVersion) {
version = trimmedVersion;
core.debug(`Using version from file: ${version}`);
} else {
core.warning(
`Version file ${versionFile} is empty, using tofu_version input: ${version}`
);
}
} catch (error) {
core.warning(
`Failed to read version from file ${versionFile}: ${error.message}. Using tofu_version input: ${version}`
);
}
}
// Gather OS details
const osPlatform = os.platform();
const osArch = os.arch();

View file

@ -3,133 +3,184 @@ const pkg = require('../releases');
describe('getRelease', () => {
function mockFetchReleases () {
const mockReleasesMeta = [{
id: 'v1.7.0-alpha2',
files: [
'tofu_1.7.0-alpha2_386.apk',
'tofu_1.7.0-alpha2_386.deb',
'tofu_1.7.0-alpha2_386.rpm',
'tofu_1.7.0-alpha2_amd64.apk',
'tofu_1.7.0-alpha2_amd64.deb',
'tofu_1.7.0-alpha2_amd64.rpm',
'tofu_1.7.0-alpha2_arm.apk',
'tofu_1.7.0-alpha2_arm.deb',
'tofu_1.7.0-alpha2_arm.rpm',
'tofu_1.7.0-alpha2_arm64.apk',
'tofu_1.7.0-alpha2_arm64.deb',
'tofu_1.7.0-alpha2_arm64.rpm',
'tofu_1.7.0-alpha2_darwin_arm64.zip',
'tofu_1.7.0-alpha2_freebsd_386.zip',
'tofu_1.7.0-alpha2_freebsd_amd64.zip',
'tofu_1.7.0-alpha2_freebsd_arm.zip',
'tofu_1.7.0-alpha2_linux_386.zip',
'tofu_1.7.0-alpha2_linux_amd64.zip',
'tofu_1.7.0-alpha2_linux_arm.zip',
'tofu_1.7.0-alpha2_linux_arm64.zip',
'tofu_1.7.0-alpha2_openbsd_386.zip',
'tofu_1.7.0-alpha2_openbsd_amd64.zip',
'tofu_1.7.0-alpha2_SHA256SUMS',
'tofu_1.7.0-alpha2_SHA256SUMS.pem',
'tofu_1.7.0-alpha2_SHA256SUMS.sig',
'tofu_1.7.0-alpha2_solaris_amd64.zip',
'tofu_1.7.0-alpha2_windows_386.zip',
'tofu_1.7.0-alpha2_windows_amd64.zip'
]
tag_name: 'v1.6.0-alpha2',
assets: [{
name: 'tofu_1.6.0-alpha2_386.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_386.apk'
}, {
name: 'tofu_1.6.0-alpha2_386.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_386.deb'
}, {
name: 'tofu_1.6.0-alpha2_386.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_386.rpm'
}, {
name: 'tofu_1.6.0-alpha2_amd64.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_amd64.apk'
}, {
name: 'tofu_1.6.0-alpha2_amd64.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_amd64.deb'
}, {
name: 'tofu_1.6.0-alpha2_amd64.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_amd64.rpm'
}, {
name: 'tofu_1.6.0-alpha2_arm.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm.apk'
}, {
name: 'tofu_1.6.0-alpha2_arm.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm.deb'
}, {
name: 'tofu_1.6.0-alpha2_arm.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm.rpm'
}, {
name: 'tofu_1.6.0-alpha2_arm64.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm64.apk'
}, {
name: 'tofu_1.6.0-alpha2_arm64.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm64.deb'
}, {
name: 'tofu_1.6.0-alpha2_arm64.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_arm64.rpm'
}, {
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_darwin_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha2_darwin_arm64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_darwin_arm64.zip'
}, {
name: 'tofu_1.6.0-alpha2_freebsd_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_freebsd_386.zip'
}, {
name: 'tofu_1.6.0-alpha2_freebsd_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_freebsd_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha2_freebsd_arm.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_freebsd_arm.zip'
}, {
name: 'tofu_1.6.0-alpha2_linux_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_linux_386.zip'
}, {
name: 'tofu_1.6.0-alpha2_linux_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_linux_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha2_linux_arm.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_linux_arm.zip'
}, {
name: 'tofu_1.6.0-alpha2_linux_arm64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_linux_arm64.zip'
}, {
name: 'tofu_1.6.0-alpha2_openbsd_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_openbsd_386.zip'
}, {
name: 'tofu_1.6.0-alpha2_openbsd_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_openbsd_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha2_SHA256SUMS',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_SHA256SUMS'
}, {
name: 'tofu_1.6.0-alpha2_SHA256SUMS.pem',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_SHA256SUMS.pem'
}, {
name: 'tofu_1.6.0-alpha2_SHA256SUMS.sig',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_SHA256SUMS.sig'
}, {
name: 'tofu_1.6.0-alpha2_solaris_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_solaris_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha2_windows_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_windows_386.zip'
}, {
name: 'tofu_1.6.0-alpha2_windows_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha2/tofu_1.6.0-alpha2_windows_amd64.zip'
}]
}, {
id: 'v1.6.0',
files: [
'tofu_1.6.0_386.apk',
'tofu_1.6.0_386.deb',
'tofu_1.6.0_386.rpm',
'tofu_1.6.0_amd64.apk',
'tofu_1.6.0_amd64.deb',
'tofu_1.6.0_amd64.rpm',
'tofu_1.6.0_arm.apk',
'tofu_1.6.0_arm.deb',
'tofu_1.6.0_arm.rpm',
'tofu_1.6.0_arm64.apk',
'tofu_1.6.0_arm64.deb',
'tofu_1.6.0_arm64.rpm',
'tofu_1.6.0_darwin_arm64.zip',
'tofu_1.6.0_freebsd_386.zip',
'tofu_1.6.0_freebsd_amd64.zip',
'tofu_1.6.0_freebsd_arm.zip',
'tofu_1.6.0_linux_386.zip',
'tofu_1.6.0_linux_amd64.zip',
'tofu_1.6.0_linux_arm.zip',
'tofu_1.6.0_linux_arm64.zip',
'tofu_1.6.0_openbsd_386.zip',
'tofu_1.6.0_openbsd_amd64.zip',
'tofu_1.6.0_SHA256SUMS',
'tofu_1.6.0_SHA256SUMS.pem',
'tofu_1.6.0_SHA256SUMS.sig',
'tofu_1.6.0_solaris_amd64.zip',
'tofu_1.6.0_windows_386.zip',
'tofu_1.6.0_windows_amd64.zip']
}, {
id: 'v1.6.0-alpha2',
files: [
'tofu_1.6.0-alpha2_386.apk',
'tofu_1.6.0-alpha2_386.deb',
'tofu_1.6.0-alpha2_386.rpm',
'tofu_1.6.0-alpha2_amd64.apk',
'tofu_1.6.0-alpha2_amd64.deb',
'tofu_1.6.0-alpha2_amd64.rpm',
'tofu_1.6.0-alpha2_arm.apk',
'tofu_1.6.0-alpha2_arm.deb',
'tofu_1.6.0-alpha2_arm.rpm',
'tofu_1.6.0-alpha2_arm64.apk',
'tofu_1.6.0-alpha2_arm64.deb',
'tofu_1.6.0-alpha2_arm64.rpm',
'tofu_1.6.0-alpha2_darwin_arm64.zip',
'tofu_1.6.0-alpha2_freebsd_386.zip',
'tofu_1.6.0-alpha2_freebsd_amd64.zip',
'tofu_1.6.0-alpha2_freebsd_arm.zip',
'tofu_1.6.0-alpha2_linux_386.zip',
'tofu_1.6.0-alpha2_linux_amd64.zip',
'tofu_1.6.0-alpha2_linux_arm.zip',
'tofu_1.6.0-alpha2_linux_arm64.zip',
'tofu_1.6.0-alpha2_openbsd_386.zip',
'tofu_1.6.0-alpha2_openbsd_amd64.zip',
'tofu_1.6.0-alpha2_SHA256SUMS',
'tofu_1.6.0-alpha2_SHA256SUMS.pem',
'tofu_1.6.0-alpha2_SHA256SUMS.sig',
'tofu_1.6.0-alpha2_solaris_amd64.zip',
'tofu_1.6.0-alpha2_windows_386.zip',
'tofu_1.6.0-alpha2_windows_amd64.zip'
]
}, {
id: 'v1.6.0-alpha1',
files: [
'tofu_1.6.0-alpha1_386.apk',
'tofu_1.6.0-alpha1_386.deb',
'tofu_1.6.0-alpha1_386.rpm',
'tofu_1.6.0-alpha1_amd64.apk',
'tofu_1.6.0-alpha1_amd64.deb',
'tofu_1.6.0-alpha1_amd64.rpm',
'tofu_1.6.0-alpha1_arm.apk',
'tofu_1.6.0-alpha1_arm.deb',
'tofu_1.6.0-alpha1_arm.rpm',
'tofu_1.6.0-alpha1_arm64.apk',
'tofu_1.6.0-alpha1_arm64.deb',
'tofu_1.6.0-alpha1_arm64.rpm',
'tofu_1.6.0-alpha1_darwin_amd64.zip',
'tofu_1.6.0-alpha1_darwin_arm64.zip',
'tofu_1.6.0-alpha1_freebsd_386.zip',
'tofu_1.6.0-alpha1_freebsd_amd64.zip',
'tofu_1.6.0-alpha1_freebsd_arm.zip',
'tofu_1.6.0-alpha1_linux_386.zip',
'tofu_1.6.0-alpha1_linux_amd64.zip',
'tofu_1.6.0-alpha1_linux_arm.zip',
'tofu_1.6.0-alpha1_linux_arm64.zip',
'tofu_1.6.0-alpha1_openbsd_386.zip',
'tofu_1.6.0-alpha1_openbsd_amd64.zip',
'tofu_1.6.0-alpha1_SHA256SUMS',
'tofu_1.6.0-alpha1_SHA256SUMS.pem',
'tofu_1.6.0-alpha1_SHA256SUMS.sig',
'tofu_1.6.0-alpha1_solaris_amd64.zip',
'tofu_1.6.0-alpha1_windows_386.zip',
'tofu_1.6.0-alpha1_windows_amd64.zip'
]
tag_name: 'v1.6.0-alpha1',
assets: [{
name: 'tofu_1.6.0-alpha1_386.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_386.apk'
}, {
name: 'tofu_1.6.0-alpha1_386.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_386.deb'
}, {
name: 'tofu_1.6.0-alpha1_386.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_386.rpm'
}, {
name: 'tofu_1.6.0-alpha1_amd64.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_amd64.apk'
}, {
name: 'tofu_1.6.0-alpha1_amd64.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_amd64.deb'
}, {
name: 'tofu_1.6.0-alpha1_amd64.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_amd64.rpm'
}, {
name: 'tofu_1.6.0-alpha1_arm.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm.apk'
}, {
name: 'tofu_1.6.0-alpha1_arm.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm.deb'
}, {
name: 'tofu_1.6.0-alpha1_arm.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm.rpm'
}, {
name: 'tofu_1.6.0-alpha1_arm64.apk',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm64.apk'
}, {
name: 'tofu_1.6.0-alpha1_arm64.deb',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm64.deb'
}, {
name: 'tofu_1.6.0-alpha1_arm64.rpm',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_arm64.rpm'
}, {
name: 'tofu_1.6.0-alpha1_darwin_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_darwin_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha1_darwin_arm64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_darwin_arm64.zip'
}, {
name: 'tofu_1.6.0-alpha1_freebsd_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_freebsd_386.zip'
}, {
name: 'tofu_1.6.0-alpha1_freebsd_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_freebsd_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha1_freebsd_arm.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_freebsd_arm.zip'
}, {
name: 'tofu_1.6.0-alpha1_linux_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_linux_386.zip'
}, {
name: 'tofu_1.6.0-alpha1_linux_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_linux_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha1_linux_arm.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_linux_arm.zip'
}, {
name: 'tofu_1.6.0-alpha1_linux_arm64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_linux_arm64.zip'
}, {
name: 'tofu_1.6.0-alpha1_openbsd_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_openbsd_386.zip'
}, {
name: 'tofu_1.6.0-alpha1_openbsd_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_openbsd_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha1_SHA256SUMS',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_SHA256SUMS'
}, {
name: 'tofu_1.6.0-alpha1_SHA256SUMS.pem',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_SHA256SUMS.pem'
}, {
name: 'tofu_1.6.0-alpha1_SHA256SUMS.sig',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_SHA256SUMS.sig'
}, {
name: 'tofu_1.6.0-alpha1_solaris_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_solaris_amd64.zip'
}, {
name: 'tofu_1.6.0-alpha1_windows_386.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_windows_386.zip'
}, {
name: 'tofu_1.6.0-alpha1_windows_amd64.zip',
browser_download_url: 'https://github.com/opentofu/opentofu/releases/download/v1.6.0-alpha1/tofu_1.6.0-alpha1_windows_amd64.zip'
}]
}];
return mockReleasesMeta.map(el => new pkg.Release(el));
@ -137,15 +188,12 @@ describe('getRelease', () => {
it.each(
[
['latest', '1.6.0'],
['latest', '1.6.0-alpha2'],
['<1.6.0-beta', '1.6.0-alpha2'],
['>1.6.0-alpha1', '1.6.0'],
['>1.6.0-alpha1', '1.6.0-alpha2'],
['>1.6.0-alpha1 <1.6.0', '1.6.0-alpha2'],
['~1.6.0-alpha', '1.6.0'],
['<=1.6.0-alpha1', '1.6.0-alpha1'],
['>1.5.0', '1.6.0'],
['>1.5.0', '1.6.0'],
['>1.7.0-alpha', '1.7.0-alpha2']
['~1.6.0-alpha', '1.6.0-alpha2'],
['<=1.6.0-alpha1', '1.6.0-alpha1']
]
)('happy path: getRelease(\'%s\') -> \'%s\'', async (input, wantVersion) => {
const want = mockFetchReleases().find(el => el.version === wantVersion);
@ -157,12 +205,8 @@ describe('getRelease', () => {
[
['foo', 'Input version cannot be used, see semver: https://semver.org/spec/v2.0.0.html', mockFetchReleases],
['2.0', 'No matching version found', mockFetchReleases],
['latest', 'No tofu releases found, please contact OpenTofu', async () => {
return null;
}],
['latest', 'No tofu releases found, please contact OpenTofu', async () => {
return [];
}]
['latest', 'No tofu releases found, please contact OpenTofu', async () => { return null; }],
['latest', 'No tofu releases found, please contact OpenTofu', async () => { return []; }]
]
)('unhappy path: getRelease(\'%s\') -> throw Error(\'%s\')', async (input, wantErrorMessage, mockFetchReleasesFn) => {
try {

View file

@ -1,176 +0,0 @@
// Node.js core
const fs = require('fs').promises;
const os = require('os');
const path = require('path');
// External
const core = require('@actions/core');
// First party
const releases = require('../releases');
const setup = require('../setup-tofu');
// Mock dependencies
jest.mock('@actions/core');
jest.mock('@actions/io', () => ({
mv: jest.fn(),
cp: jest.fn(),
mkdirP: jest.fn()
}));
jest.mock('@actions/tool-cache', () => ({
downloadTool: jest.fn(),
extractZip: jest.fn()
}));
// Mock releases.js so setup-tofu.js can be tested in isolation
jest.mock('../releases');
// Set up global test fixtures
const fallbackVersion = 'latest';
let tempDir;
let tempDirPath;
let version = '1.10.5';
let versionFile;
let versionFileName = '.opentofu-version';
describe('setup-tofu', () => {
beforeAll(async () => {
// Mock dependencies
const tc = require('@actions/tool-cache');
tc.downloadTool.mockResolvedValue('/mock/download/path');
tc.extractZip.mockResolvedValue('/mock/extract/path');
const io = require('@actions/io');
io.mv.mockResolvedValue();
io.cp.mockResolvedValue();
io.mkdirP.mockResolvedValue();
const mockRelease = {
getBuild: jest.fn().mockReturnValue({ url: 'mock-url' })
};
releases.getRelease.mockResolvedValue(mockRelease);
// Write version file to temporary directory
tempDirPath = path.join(os.tmpdir(), 'setup-tofu-');
tempDir = await fs.mkdtemp(tempDirPath);
versionFile = path.join(tempDir, versionFileName);
await fs.writeFile(versionFile, `${version}\n`);
// Mock action inputs to return default values
core.getInput.mockImplementation((name) => {
const defaults = {
tofu_version: fallbackVersion,
tofu_version_file: versionFile,
cli_config_credentials_hostname: '',
cli_config_credentials_token: '',
tofu_wrapper: 'true',
github_token: ''
};
return defaults[name] || '';
});
// Mock environment variables
process.env.GITHUB_TOKEN = 'mock-github-token';
});
beforeEach(() => {
jest.clearAllMocks();
});
afterAll(async () => {
delete process.env.GITHUB_TOKEN;
});
describe('tofu_version_file functionality', () => {
it('should read version from file when tofu_version_file is provided', async () => {
jest.spyOn(fs, 'readFile');
await setup();
expect(releases.getRelease).toHaveBeenCalledWith(
version, process.env.GITHUB_TOKEN
);
expect(fs.readFile).toHaveBeenCalled();
});
it('should handle empty version file gracefully', async () => {
jest.spyOn(fs, 'readFile');
version = ' ';
versionFileName = '.opentofu-version-empty';
versionFile = path.join(tempDir, versionFileName);
await fs.writeFile(versionFile, `${version}\n`);
core.getInput.mockImplementation((name) => {
if (name === 'tofu_version_file') {
return versionFile;
}
if (name === 'tofu_version') {
return fallbackVersion;
}
return '';
});
await setup();
expect(releases.getRelease).toHaveBeenCalledWith(
fallbackVersion, process.env.GITHUB_TOKEN
);
expect(core.warning).toHaveBeenCalledWith(
expect.stringContaining(`Version file ${versionFile} is empty`)
);
expect(fs.readFile).toHaveBeenCalled();
});
it('should handle file read errors gracefully', async () => {
jest.spyOn(fs, 'readFile');
versionFileName = '.opentofu-version-file-does-not-exist';
versionFile = path.join(tempDir, versionFileName);
core.getInput.mockImplementation((name) => {
if (name === 'tofu_version_file') {
return versionFile;
}
if (name === 'tofu_version') {
return fallbackVersion;
}
return '';
});
await setup();
expect(releases.getRelease).toHaveBeenCalledWith(
fallbackVersion, process.env.GITHUB_TOKEN
);
expect(core.warning).toHaveBeenCalledWith(
expect.stringContaining(`Failed to read version from file ${versionFile}`)
);
expect(fs.readFile).toHaveBeenCalled();
});
it('should not read file when tofu_version_file is not provided', async () => {
jest.spyOn(fs, 'readFile');
core.getInput.mockImplementation((name) => {
if (name === 'tofu_version') {
return fallbackVersion;
}
return '';
});
await setup();
expect(releases.getRelease).toHaveBeenCalledWith(
fallbackVersion, process.env.GITHUB_TOKEN
);
expect(fs.readFile).not.toHaveBeenCalled();
});
});
});

3269
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -19,16 +19,16 @@
"keywords": [],
"author": "",
"dependencies": {
"@actions/core": "2.0.1",
"@actions/exec": "2.0.0",
"@actions/io": "2.0.0",
"@actions/tool-cache": "2.0.2",
"semver": "7.7.3"
"@actions/core": "1.10.1",
"@actions/exec": "1.1.1",
"@actions/io": "1.1.3",
"@actions/tool-cache": "2.0.1",
"semver": "7.5.4"
},
"devDependencies": {
"@vercel/ncc": "0.38.4",
"husky": "9.1.7",
"jest": "30.2.0",
"@vercel/ncc": "0.38.1",
"husky": "8.0.3",
"jest": "29.7.0",
"semistandard": "17.0.0"
},
"semistandard": {

View file

@ -9,8 +9,7 @@
*
* @example
* // Instantiate a new listener
* // stream is used to write the data before waiting for the listener to complete
* const listener = new OutputListener(stream);
* const listener = new OutputListener();
* // Register listener against STDOUT stream
* await exec.exec('ls', ['-ltr'], {
* listeners: {
@ -21,14 +20,12 @@
* console.log(listener.contents);
*/
class OutputListener {
constructor (stream) {
constructor () {
this._buff = [];
this._stream = stream;
}
get listener () {
const listen = function listen (data) {
this._stream.write(data);
this._buff.push(data);
};
return listen.bind(this);

View file

@ -4,18 +4,14 @@
*/
const OutputListener = require('../lib/output-listener');
const { PassThrough } = require('stream');
describe('output-listener', () => {
it('receives and exposes data', () => {
const stream = new PassThrough();
const listener = new OutputListener(stream);
const listener = new OutputListener();
const listen = listener.listener;
listen(Buffer.from('foo'));
expect(stream.read()).toEqual(Buffer.from('foo'));
listen(Buffer.from('bar'));
expect(stream.read()).toEqual(Buffer.from('bar'));
listen(Buffer.from('baz'));
expect(stream.read()).toEqual(Buffer.from('baz'));
expect(listener.contents).toEqual('foobarbaz');
});
});

View file

@ -22,8 +22,8 @@ async function checkTofu () {
await checkTofu();
// Create listeners to receive output (in memory) as well
const stdout = new OutputListener(process.stdout);
const stderr = new OutputListener(process.stderr);
const stdout = new OutputListener();
const stderr = new OutputListener();
const listeners = {
stdout: stdout.listener,
stderr: stderr.listener
@ -33,10 +33,13 @@ async function checkTofu () {
const args = process.argv.slice(2);
const options = {
listeners,
ignoreReturnCode: true,
silent: true // don't print "[command...]" into stdout: https://github.com/actions/toolkit/issues/649
ignoreReturnCode: true
};
const exitCode = await exec(pathToCLI, args, options);
core.debug(`OpenTofu exited with code ${exitCode}.`);
core.debug(`stdout: ${stdout.contents}`);
core.debug(`stderr: ${stderr.contents}`);
core.debug(`exitcode: ${exitCode}`);
// Set outputs, result, exitcode, and stderr
core.setOutput('stdout', stdout.contents);