diff --git a/internal/virtualenvironment/virtualenvironment.go b/internal/virtualenvironment/virtualenvironment.go index 055bc890fc..90d9ea4b77 100644 --- a/internal/virtualenvironment/virtualenvironment.go +++ b/internal/virtualenvironment/virtualenvironment.go @@ -53,6 +53,9 @@ func (v *VirtualEnvironment) GetEnv(inherit bool, useExecutors bool, projectDir, return envMap, locale.WrapError(err, "err_parse_project", "", configFile) } for _, constant := range pj.Constants() { + if !constant.Export() { + continue + } v, err := constant.Value() envMap[constant.Name()] = strings.Replace(v, "\n", `\n`, -1) if err != nil { diff --git a/pkg/project/project.go b/pkg/project/project.go index 448ffb6206..db4b0a6411 100644 --- a/pkg/project/project.go +++ b/pkg/project/project.go @@ -369,6 +369,9 @@ func (c *Constant) Value() (string, error) { return ExpandFromProject(c.constant.Value, c.project) } +// Export returns whether or not the constant should be exported to an activated shell environment. +func (c *Constant) Export() bool { return c.constant.ConstantFields.Export } + // SecretScope defines the scope of a secret type SecretScope string diff --git a/pkg/projectfile/projectfile.go b/pkg/projectfile/projectfile.go index c89b2857e4..a47868ada5 100644 --- a/pkg/projectfile/projectfile.go +++ b/pkg/projectfile/projectfile.go @@ -113,6 +113,7 @@ type Build map[string]string // ConstantFields are the common fields for the Constant type. This is required // for type composition related to its yaml.Unmarshaler implementation. type ConstantFields struct { + Export bool `yaml:"export"` Conditional Conditional `yaml:"if"` } diff --git a/pkg/projectfile/projectfile_test.go b/pkg/projectfile/projectfile_test.go index b3b9725d32..24fb183536 100644 --- a/pkg/projectfile/projectfile_test.go +++ b/pkg/projectfile/projectfile_test.go @@ -110,13 +110,15 @@ func TestConstantStruct(t *testing.T) { constant := Constant{} dat := strings.TrimSpace(` name: valueForName -value: valueForConstant`) +value: valueForConstant +export: true`) err := yaml.Unmarshal([]byte(dat), &constant) assert.Nil(t, err, "Should not throw an error") assert.Equal(t, "valueForName", constant.Name, "Name should be set") assert.Equal(t, "valueForConstant", constant.Value, "Constant should be set") + assert.Equal(t, true, constant.Export, "Constant export should be set") } func TestSecretStruct(t *testing.T) { @@ -150,6 +152,7 @@ func TestParse(t *testing.T) { assert.NotEmpty(t, project.Constants[0].Name, "Constant name should be set") assert.NotEmpty(t, project.Constants[0].Value, "Constant value should be set") + assert.False(t, project.Constants[0].Export, "Constant export value should not be set") assert.NotEmpty(t, project.Secrets.User[0].Name, "Variable name should be set") assert.NotEmpty(t, project.Secrets.Project[0].Name, "Variable name should be set") diff --git a/test/integration/shell_int_test.go b/test/integration/shell_int_test.go index f731c51ab4..9569bc5d4f 100644 --- a/test/integration/shell_int_test.go +++ b/test/integration/shell_int_test.go @@ -470,6 +470,47 @@ func (suite *ShellIntegrationTestSuite) TestProjectOrder() { cp.ExpectNotExitCode(0) } +func (suite *ShellIntegrationTestSuite) TestExportedConstants() { + suite.OnlyRunForTags(tagsuite.Shell) + ts := e2e.New(suite.T(), false) + defer ts.Close() + + ts.PrepareProject("ActiveState-CLI/Perl-5.32", "a4762408-def6-41e4-b709-4cb548765005") + suite.Require().NoError(fileutils.AmendFile(filepath.Join(ts.Dirs.Work, constants.ConfigFileName), []byte(` +constants: + - name: foo + value: bar + - name: baz + value: quux + export: true`), fileutils.AmendByAppend)) + + cp := ts.SpawnWithOpts( + e2e.OptArgs("shell"), + e2e.OptAppendEnv(constants.DisableRuntime+"=false"), + ) + cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) + + cp.ExpectInput() + if runtime.GOOS == "windows" { + cp.SendLine("echo %foo%") + } else { + cp.SendLine("echo $foo") + } + cp.ExpectInput() + suite.Assert().NotContains(cp.Snapshot(), "bar", "variable 'foo' was exported, but should not have been") + + if runtime.GOOS == "windows" { + cp.SendLine("echo %baz%") + } else { + cp.SendLine("echo $baz") + } + cp.Expect("quux") + + cp.SendLine("exit") + cp.Expect("Deactivated") + cp.ExpectExit() // exit code varies depending on shell; just assert the shell exited +} + func TestShellIntegrationTestSuite(t *testing.T) { suite.Run(t, new(ShellIntegrationTestSuite)) }