Files
opentf/internal/checks/status.go
Martin Atkins e74bf2d0a1 go.mod: Use the new "tool" directive
Previously the Go toolchain had no explicit support for "tools" and so we
used the typical Go community workaround of adding "tools.go" files (two,
for some reason) that existed only to trick the Go toolchain into
considering the tools as dependencies we could track in go.mod.

Go 1.24 introduced explicit support for tracking tools as part of go.mod,
and the ability to run those using "go tool" instead of "go run", and so
this commit switches us over to using that strategy for everything we were
previously managing in tools.go.

There are some intentional exceptions here:

- The protobuf-compile script can't use "go tool" or "go run" because the
  tools in question are run only indirectly through protoc. However, we
  do still use the "tool" directive in go.mod to tell the Go toolchain that
  we depend on those tools, so that it'll track which versions we are
  currently using as part of go.mod.
- Our golangci-lint Makefile target uses "go run" to run a specific
  version of golangci-lint. We _intentionally_ don't consider that tool
  to be a direct dependency of OpenTofu because it has a lot of indirect
  dependencies that would pollute our go.mod file. Therefore that continues
  to use "go run" after this commit.
- Both of our tools.go files previously referred to
  github.com/nishanths/exhaustive , but nothing actually appears to be
  using that tool in the current OpenTofu tree, so it's no longer a
  dependency after this commit.

All of the dependencies we have _only_ for tools are now classified as
"indirect" in the go.mod file. This is the default behavior of the Go
toolchain and appears to be motivated by making it clearer that these
modules do not contribute anything to the runtime behavior of OpenTofu.
This also corrected a historical oddity in our go.mod where for some reason
the "indirect" dependencies had been split across two different "require"
directives; they are now all grouped together in a single directive.

Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
2025-10-10 07:06:56 -03:00

80 lines
2.5 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package checks
import (
"fmt"
"github.com/zclconf/go-cty/cty"
)
// Status represents the status of an individual check associated with a
// checkable object.
type Status rune
//go:generate go tool golang.org/x/tools/cmd/stringer -type=Status
const (
// StatusUnknown represents that there is not yet a conclusive result
// for the check, either because we haven't yet visited its associated
// object or because the check condition itself depends on a value not
// yet known during planning.
StatusUnknown Status = 0
// NOTE: Our implementation relies on StatusUnknown being the zero value
// of Status.
// StatusPass represents that OpenTofu Core has evaluated the check's
// condition and it returned true, indicating success.
StatusPass Status = 'P'
// StatusFail represents that OpenTofu Core has evaluated the check's
// condition and it returned false, indicating failure.
StatusFail Status = 'F'
// StatusError represents that OpenTofu Core tried to evaluate the check's
// condition but encountered an error while evaluating the check expression.
//
// This is different than StatusFail because StatusFail indicates that
// the condition was valid and returned false, whereas StatusError
// indicates that the condition was not valid at all.
StatusError Status = 'E'
)
// StatusForCtyValue returns the Status value corresponding to the given
// cty Value, which must be one of either cty.True, cty.False, or
// cty.UnknownVal(cty.Bool) or else this function will panic.
//
// The current behavior of this function is:
//
// cty.True StatusPass
// cty.False StatusFail
// cty.UnknownVal(cty.Bool) StatusUnknown
//
// Any other input will panic. Note that there's no value that can produce
// StatusError, because in case of a condition error there will not typically
// be a result value at all.
func StatusForCtyValue(v cty.Value) Status {
if !v.Type().Equals(cty.Bool) {
panic(fmt.Sprintf("cannot use %s as check status", v.Type().FriendlyName()))
}
if v.IsNull() {
panic("cannot use null as check status")
}
switch {
case v == cty.True:
return StatusPass
case v == cty.False:
return StatusFail
case !v.IsKnown():
return StatusUnknown
default:
// Should be impossible to get here unless something particularly
// weird is going on, like a marked condition result.
panic(fmt.Sprintf("cannot use %#v as check status", v))
}
}