github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/pkg/project/expander_test.go (about)

     1  package project_test
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"gopkg.in/yaml.v2"
    14  
    15  	"github.com/ActiveState/cli/internal/fileutils"
    16  	"github.com/ActiveState/cli/internal/language"
    17  
    18  	"github.com/ActiveState/cli/pkg/project"
    19  	"github.com/ActiveState/cli/pkg/projectfile"
    20  )
    21  
    22  func loadProject(t *testing.T) *project.Project {
    23  	projectfile.Reset()
    24  
    25  	pjFile := &projectfile.Project{}
    26  	contents := strings.TrimSpace(`
    27  project: "https://platform.activestate.com/Expander/general?branch=main"
    28  lock: branchname@0.0.0-SHA123abcd
    29  constants:
    30    - name: constant
    31      value: value
    32    - name: recursive
    33      value: recursive $constants.constant
    34  secrets:
    35    project:
    36      - name: proj-secret
    37    user:
    38      - name: user-proj-secret
    39  scripts:
    40    - name: test
    41      value: make test
    42    - name: recursive
    43      value: echo $scripts.recursive
    44    - name: pythonScript
    45      language: python3
    46      value: scriptValue
    47    - name: scriptPath
    48      value: $scripts.pythonScript.path()
    49    - name: scriptRecursive
    50      value: $scripts.scriptRecursive.path()
    51    - name: bashScriptPath
    52      language: bash
    53      value: ${scripts.pythonScript.path()}
    54  `)
    55  
    56  	err := yaml.Unmarshal([]byte(contents), pjFile)
    57  	assert.Nil(t, err, "Unmarshalled YAML")
    58  
    59  	require.NoError(t, pjFile.Init())
    60  
    61  	require.NoError(t, pjFile.Persist())
    62  
    63  	proj, err := project.Get()
    64  	require.NoError(t, err)
    65  
    66  	return proj
    67  }
    68  
    69  func TestExpandProject(t *testing.T) {
    70  	prj := loadProject(t)
    71  	prj.Source().SetPath(fmt.Sprintf("spoofed path%sactivestate.yaml", string(os.PathSeparator)))
    72  
    73  	expanded, err := project.ExpandFromProject("$project.url()", prj)
    74  	require.NoError(t, err)
    75  	assert.Equal(t, prj.URL(), expanded)
    76  
    77  	expanded, err = project.ExpandFromProject("$project.branch()", prj)
    78  	require.NoError(t, err)
    79  	assert.Equal(t, "main", expanded)
    80  
    81  	expanded, err = project.ExpandFromProject("$project.owner()", prj)
    82  	require.NoError(t, err)
    83  	assert.Equal(t, "Expander", expanded)
    84  
    85  	expanded, err = project.ExpandFromProject("$project.name()", prj)
    86  	require.NoError(t, err)
    87  	assert.Equal(t, "general", expanded)
    88  
    89  	expanded, err = project.ExpandFromProject("$project.namespace()", prj)
    90  	require.NoError(t, err)
    91  	assert.Equal(t, "Expander/general", expanded)
    92  
    93  	expanded, err = project.ExpandFromProject("$project.path()", prj)
    94  	require.NoError(t, err)
    95  	assert.Equal(t, "spoofed path", expanded)
    96  
    97  	if runtime.GOOS == "windows" {
    98  		prj.Source().SetPath(`c:\another\spoofed path\activestate.yaml`)
    99  		expanded, err = project.ExpandFromProjectBashifyPaths("$project.path()", prj)
   100  		require.NoError(t, err)
   101  		assert.Equal(t, `/c/another/spoofed\ path`, expanded)
   102  	}
   103  }
   104  
   105  func TestExpandTopLevel(t *testing.T) {
   106  	prj := loadProject(t)
   107  
   108  	expanded, err := project.ExpandFromProject("$project", prj)
   109  	assert.NoError(t, err, "Ran without failure")
   110  
   111  	assert.Equal(t, "https://platform.activestate.com/Expander/general?branch=main", expanded)
   112  
   113  	expanded, err = project.ExpandFromProject("$lock", prj)
   114  	assert.NoError(t, err, "Ran without failure")
   115  	assert.Equal(t, "branchname@0.0.0-SHA123abcd", expanded)
   116  
   117  	expanded, err = project.ExpandFromProject("$notcovered", prj)
   118  	assert.NoError(t, err, "Ran without failure")
   119  	assert.Equal(t, "$notcovered", expanded)
   120  }
   121  
   122  func TestExpandProjectScript(t *testing.T) {
   123  	prj := loadProject(t)
   124  
   125  	expanded, err := project.ExpandFromProject("$ $scripts.test", prj)
   126  	assert.NoError(t, err, "Ran without failure")
   127  	assert.Equal(t, "$ make test", expanded, "Expanded simple script")
   128  }
   129  
   130  func TestExpandProjectConstant(t *testing.T) {
   131  	prj := loadProject(t)
   132  
   133  	expanded, err := project.ExpandFromProject("$ $constants.constant", prj)
   134  	assert.NoError(t, err, "Ran without failure")
   135  	assert.Equal(t, "$ value", expanded, "Expanded simple constant")
   136  
   137  	expanded, err = project.ExpandFromProject("$ $constants.recursive", prj)
   138  	assert.NoError(t, err, "Ran without failure")
   139  	assert.Equal(t, "$ recursive value", expanded, "Expanded recursive constant")
   140  }
   141  
   142  func TestExpandProjectSecret(t *testing.T) {
   143  	pj := loadProject(t)
   144  
   145  	err := project.RegisterExpander("secrets", func(_ string, category string, meta string, isFunction bool, ctx *project.Expansion) (string, error) {
   146  		if category == project.ProjectCategory {
   147  			return "proj-value", nil
   148  		}
   149  		return "user-proj-value", nil
   150  	})
   151  	require.NoError(t, err)
   152  
   153  	expanded, err := project.ExpandFromProject("$ $secrets.user.user-proj-secret", pj)
   154  	assert.NoError(t, err, "Ran without failure")
   155  	assert.Equal(t, "$ user-proj-value", expanded, "Expanded simple constant")
   156  
   157  	expanded, err = project.ExpandFromProject("$ $secrets.project.proj-secret", pj)
   158  	assert.NoError(t, err, "Ran without failure")
   159  	assert.Equal(t, "$ proj-value", expanded, "Expanded simple constant")
   160  }
   161  
   162  func TestExpandProjectAlternateSyntax(t *testing.T) {
   163  	prj := loadProject(t)
   164  
   165  	expanded, err := project.ExpandFromProject("${project.name()}", prj)
   166  	assert.NoError(t, err, "Ran without failure")
   167  	assert.Equal(t, "general", expanded, "Expanded project variable")
   168  }
   169  
   170  func TestExpandProjectUnknownCategory(t *testing.T) {
   171  	prj := loadProject(t)
   172  
   173  	expanded, err := project.ExpandFromProject("$unknown.unknown", prj)
   174  	assert.NoError(t, err, "Ran without failure")
   175  	assert.Equal(t, "$unknown.unknown", expanded, "Didn't expand variable it doesnt own")
   176  }
   177  
   178  func TestExpandProjectInfiniteRecursion(t *testing.T) {
   179  	prj := loadProject(t)
   180  
   181  	_, err := project.ExpandFromProject("$scripts.recursive", prj)
   182  	require.Error(t, err, "Ran with failure")
   183  	assert.Contains(t, err.Error(), "Infinite recursion trying to expand variable", "Handled unknown category")
   184  }
   185  
   186  func TestExpandDashed(t *testing.T) {
   187  	projectFile := &projectfile.Project{}
   188  	contents := strings.TrimSpace(`
   189  project: "https://platform.activestate.com/Expander/Dashed"
   190  scripts:
   191    - name: foo-bar
   192      value: bar
   193  `)
   194  
   195  	err := yaml.Unmarshal([]byte(contents), projectFile)
   196  	assert.Nil(t, err, "Unmarshalled YAML")
   197  	require.NoError(t, projectFile.Persist())
   198  	prj, err := project.Get()
   199  	require.NoError(t, err)
   200  
   201  	expanded, err := project.ExpandFromProject("- $scripts.foo-bar -", prj)
   202  	assert.NoError(t, err, "Ran without failure")
   203  	assert.Equal(t, "- bar -", expanded)
   204  	projectfile.Reset()
   205  }
   206  
   207  func TestExpandScriptPath(t *testing.T) {
   208  	prj := loadProject(t)
   209  
   210  	expanded, err := project.ExpandFromProject("$scripts.scriptPath", prj)
   211  	assert.NoError(t, err, "Ran without failure")
   212  	assert.True(t, strings.HasSuffix(expanded, language.Python3.Ext()), fmt.Sprintf("%s should have suffix %s", expanded, language.Python3.Ext()))
   213  
   214  	contents, err := fileutils.ReadFile(expanded)
   215  	require.NoError(t, err)
   216  	assert.Contains(t, string(contents), language.Python3.Header(), "Has Python3 header")
   217  	assert.Contains(t, string(contents), "scriptValue", "Contains intended script value")
   218  }
   219  
   220  func TestExpandScriptPathRecursive(t *testing.T) {
   221  	prj := loadProject(t)
   222  
   223  	expanded, err := project.ExpandFromProject("$scripts.scriptRecursive", prj)
   224  	assert.NoError(t, err, "Ran without failure")
   225  
   226  	contents, err := fileutils.ReadFile(expanded)
   227  	require.NoError(t, err)
   228  	assert.NotContains(t, contents, "$scripts.scriptRecursive.path()")
   229  }
   230  
   231  func TestExpandBashScriptPath(t *testing.T) {
   232  	prj := loadProject(t)
   233  	script := prj.ScriptByName("bashScriptPath")
   234  	require.NotNil(t, script, "bashScriptPath script does not exist")
   235  	value, err := script.Value()
   236  	require.NoError(t, err)
   237  	assert.Contains(t, value, "/pythonScript") // assert bash backslashes, even on Windows
   238  }