diff --git a/.gitignore b/.gitignore index 0a04d40e8..3844d0a09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /docs/public/ /docs/content/operator +/docs/sources/ /bin /porter .DS_Store diff --git a/Makefile b/Makefile index de3e30238..ce9d6a661 100644 --- a/Makefile +++ b/Makefile @@ -47,10 +47,6 @@ test-integration: test-smoke: go run mage.go -v TestSmoke -.PHONY: docs -docs: - go run mage.go -v docs - publish: publish-bin publish-mixins publish-images publish-bin: diff --git a/mage/docs/docs.go b/mage/docs/docs.go index 3c449fd06..519f5e63c 100644 --- a/mage/docs/docs.go +++ b/mage/docs/docs.go @@ -20,6 +20,10 @@ var must = shx.CommandBuilder{StopOnError: true} const ( LocalOperatorRepositoryEnv = "PORTER_OPERATOR_REPOSITORY" PreviewContainer = "porter-docs" + + // DefaultOperatorSourceDir is the directory where the Porter Operator docs + // are cloned when LocalOperatorRepositoryEnv was not specified. + DefaultOperatorSourceDir = "docs/sources/operator" ) // Generate Porter's static website. Used by Netlify. @@ -43,7 +47,7 @@ func removePreviewContainer() { // Preview the website documentation. func DocsPreview() { mg.Deps(removePreviewContainer) - operatorRepo := prepareOperatorRepo() + operatorRepo := ensureOperatorRepository() operatorDocs, err := filepath.Abs(filepath.Join(operatorRepo, "docs/content")) mgx.Must(err) @@ -76,46 +80,61 @@ func DocsPreview() { // clone the other doc repos if they don't exist // use a local copy as defined in PORTER_OPERATOR_REPOSITORY if available func linkOperatorDocs() { - docsDest := "docs/content/operator" - err := os.RemoveAll(docsDest) + // Remove the old symlink in case the source has moved + operatorSymlink := "docs/content/operator" + err := os.RemoveAll(operatorSymlink) if !os.IsNotExist(err) { mgx.Must(err) } - repoPath := prepareOperatorRepo() + repoPath := ensureOperatorRepository() contentPath, _ := filepath.Abs("docs/content") relPath, _ := filepath.Rel(contentPath, filepath.Join(repoPath, "docs/content")) - log.Println("ln -s", relPath, docsDest) - mgx.Must(os.Symlink(relPath, docsDest)) + log.Println("ln -s", relPath, operatorSymlink) + mgx.Must(os.Symlink(relPath, operatorSymlink)) } -// returns the location of the docs repo -func prepareOperatorRepo() string { +// Ensures that we have an operator repository and returns its location +func ensureOperatorRepository() string { + repoPath, err := ensureOperatorRepositoryIn(os.Getenv(LocalOperatorRepositoryEnv), DefaultOperatorSourceDir) + mgx.Must(err) + return repoPath +} + +// Checks if the repository in localRepo exists and return it +// otherwise clone the repository into defaultRepo, updating with the latest changes if already cloned. +func ensureOperatorRepositoryIn(localRepo string, defaultRepo string) (string, error) { // Check if we are using a local repo - if localRepo, ok := os.LookupEnv(LocalOperatorRepositoryEnv); ok { - if localRepo != "" { - if _, err := os.Stat(localRepo); err != nil { - log.Printf("%s %s does not exist, ignoring\n", LocalOperatorRepositoryEnv, localRepo) - os.Unsetenv(LocalOperatorRepositoryEnv) - } + if localRepo != "" { + if _, err := os.Stat(localRepo); err != nil { + log.Printf("%s %s does not exist, ignoring\n", LocalOperatorRepositoryEnv, localRepo) + os.Unsetenv(LocalOperatorRepositoryEnv) } else { log.Printf("Using operator repository at %s\n", localRepo) - return localRepo + return localRepo, nil } } - // Clone the repo - cloneDestination, _ := filepath.Abs("docs/sources/operator") - _, err := os.Stat(cloneDestination) - if err == nil { // Already cloned - log.Println("Operator repository already cloned, skipping") - return cloneDestination - } - if !os.IsNotExist(err) { - mgx.Must(err) + // Clone the repo, and ensure it is up-to-date + cloneDestination, _ := filepath.Abs(defaultRepo) + _, err := os.Stat(filepath.Join(cloneDestination, ".git")) + if err != nil && !os.IsNotExist(err) { + return "", err + } else if err == nil { + log.Println("Operator repository already cloned, updating") + if err = shx.Command("git", "fetch").In(cloneDestination).Run(); err != nil { + return "", err + } + if err = shx.Command("git", "reset", "--hard", "FETCH_HEAD").In(cloneDestination).Run(); err != nil { + return "", err + } + return cloneDestination, nil } log.Println("Cloning operator repository") - must.Run("git", "clone", "https://github.com/getporter/operator.git", cloneDestination) - return cloneDestination + os.RemoveAll(cloneDestination) // if the path existed but wasn't a git repo, we want to remove it and start fresh + if err = shx.Run("git", "clone", "https://github.com/getporter/operator.git", cloneDestination); err != nil { + return "", err + } + return cloneDestination, nil } diff --git a/mage/docs/docs_test.go b/mage/docs/docs_test.go new file mode 100644 index 000000000..0b0dc646b --- /dev/null +++ b/mage/docs/docs_test.go @@ -0,0 +1,74 @@ +package docs + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/carolynvs/magex/shx" + "github.com/stretchr/testify/require" +) + +func TestEnsureOperatorRepository(t *testing.T) { + t.Run("has local repo", func(t *testing.T) { + tmp, err := ioutil.TempDir("", "porter-docs-test") + require.NoError(t, err) + defer os.RemoveAll(tmp) + + resolvedPath, err := ensureOperatorRepositoryIn(tmp, "") + require.NoError(t, err) + require.Equal(t, tmp, resolvedPath) + }) + + t.Run("missing local repo", func(t *testing.T) { + tmp, err := ioutil.TempDir("", "porter-docs-test") + require.NoError(t, err) + defer os.RemoveAll(tmp) + + resolvedPath, err := ensureOperatorRepositoryIn("missing", tmp) + require.NoError(t, err) + require.Equal(t, tmp, resolvedPath) + }) + + t.Run("local repo unset", func(t *testing.T) { + tmp, err := ioutil.TempDir("", "porter-docs-test") + require.NoError(t, err) + defer os.RemoveAll(tmp) + + resolvedPath, err := ensureOperatorRepositoryIn("", tmp) + require.NoError(t, err) + require.Equal(t, tmp, resolvedPath) + }) + + t.Run("empty default path clones repo", func(t *testing.T) { + tmp, err := ioutil.TempDir("", "porter-docs-test") + require.NoError(t, err) + defer os.RemoveAll(tmp) + + resolvedPath, err := ensureOperatorRepositoryIn("", tmp) + require.NoError(t, err) + require.Equal(t, tmp, resolvedPath) + + err = shx.Command("git", "status").In(resolvedPath).RunE() + require.NoError(t, err, "clone failed") + }) + + t.Run("changes in default path are reset", func(t *testing.T) { + tmp, err := ioutil.TempDir("", "porter-docs-test") + require.NoError(t, err) + defer os.RemoveAll(tmp) + + repoPath, err := ensureOperatorRepositoryIn("", tmp) + require.NoError(t, err) + + // make a change + readme := filepath.Join(repoPath, "README.md") + require.NoError(t, os.Remove(readme)) + + // Make sure rerunning resets the change + repoPath, err = ensureOperatorRepositoryIn("", tmp) + require.NoError(t, err) + require.FileExists(t, readme) + }) +} diff --git a/netlify.toml b/netlify.toml index 7ca61f91d..b9b8aaca6 100644 --- a/netlify.toml +++ b/netlify.toml @@ -3,13 +3,13 @@ [build] publish = "docs/public" - command = "make docs" + command = "go run mage.go -v docs" [build.environment] HUGO_VERSION = "0.78.1" [context.branch-deploy] - command = "make docs BASEURL=https://${BRANCH/\//-}.porter.sh/" + command = "BASEURL=https://${BRANCH/\//-}.porter.sh/ && go run mage.go -v docs" [context.deploy-preview] - command = "make docs BASEURL=$DEPLOY_PRIME_URL/" \ No newline at end of file + command = "BASEURL=$DEPLOY_PRIME_URL/ && go run mage.go -v docs"