get.porter.sh/porter@v1.3.0/mage/docs/docs.go (about) 1 package docs 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "os/user" 8 "path/filepath" 9 "strings" 10 "time" 11 12 "get.porter.sh/magefiles/docker" 13 "github.com/magefile/mage/mg" 14 "github.com/uwu-tools/magex/mgx" 15 "github.com/uwu-tools/magex/shx" 16 ) 17 18 var must = shx.CommandBuilder{StopOnError: true} 19 20 const ( 21 LocalOperatorRepositoryEnv = "PORTER_OPERATOR_REPOSITORY" 22 PreviewContainer = "porter-docs" 23 24 // DefaultOperatorSourceDir is the directory where the Porter Operator docs 25 // are cloned when LocalOperatorRepositoryEnv was not specified. 26 DefaultOperatorSourceDir = "docs/sources/operator" 27 ) 28 29 // Build the website in preparation for deploying to the production website on Netlify. 30 // Uses symlinks so it won't work on Windows. Don't run locally, use DocsPreview instead. 31 func Docs() { 32 mg.SerialDeps(linkOperatorDocs) 33 34 cmd := must.Command("hugo", "--source", "docs/") 35 baseURL := os.Getenv("BASEURL") 36 if baseURL != "" { 37 cmd.Args("-b", baseURL) 38 } 39 mgx.Must(cmd.RunV()) 40 } 41 42 func removePreviewContainer() { 43 err := docker.RemoveContainer(PreviewContainer) 44 mgx.Must(err) 45 } 46 47 // Preview the website locally using a Docker container. 48 func DocsPreview() { 49 mg.Deps(removePreviewContainer) 50 operatorRepo := ensureOperatorRepository() 51 operatorDocs, err := filepath.Abs(filepath.Join(operatorRepo, "docs/content")) 52 mgx.Must(err) 53 54 // TODO: run on a random port, and then read the output to get the container id and then retrieve the port used 55 56 currentUser, err := user.Current() 57 if err != nil { 58 currentUser = &user.User{Uid: "0", Gid: "0"} 59 } 60 setDockerUser := fmt.Sprintf("--user=%s:%s", currentUser.Uid, currentUser.Gid) 61 pwd, _ := os.Getwd() 62 err = must.Run("docker", "run", "-d", "-v", pwd+":/src", 63 "-v", operatorDocs+":/src/docs/content/operator", 64 setDockerUser, 65 "-p", "1313:1313", "--name", PreviewContainer, "-w", "/src/docs", 66 "klakegg/hugo:0.78.1-ext-alpine", "server", "-D", "-F", "--noHTTPCache", 67 "--watch", "--bind=0.0.0.0") 68 mgx.Must(err) 69 70 for { 71 output, _ := must.OutputS("docker", "logs", "porter-docs") 72 if strings.Contains(output, "Web Server is available") { 73 break 74 } 75 time.Sleep(time.Second) 76 } 77 78 err = must.Run("open", "http://localhost:1313/docs/") 79 mgx.Must(err) 80 } 81 82 // Build a branch preview of the website. 83 func DocsBranchPreview() { 84 setBranchBaseURL() 85 Docs() 86 } 87 88 func setBranchBaseURL() { 89 // Change the branch to a URL safe slug, e.g. release/v1 -> release-v1 90 escapedBranch := strings.ReplaceAll(os.Getenv("BRANCH"), "/", "-") 91 // Append a trailing / to the URL for use in Hugo 92 baseURL := fmt.Sprintf("https://%s.porter.sh/", escapedBranch) 93 os.Setenv("BASEURL", baseURL) 94 } 95 96 // Build a pull request preview of the website. 97 func DocsPullRequestPreview() { 98 setPullRequestBaseURL() 99 Docs() 100 } 101 102 func setPullRequestBaseURL() { 103 // Append a trailing / to netlify preview domain name for use in Hugo 104 baseURL := fmt.Sprintf("%s/", os.Getenv("DEPLOY_PRIME_URL")) 105 os.Setenv("BASEURL", baseURL) 106 } 107 108 // clone the other doc repos if they don't exist 109 // use a local copy as defined in PORTER_OPERATOR_REPOSITORY if available 110 func linkOperatorDocs() { 111 // Remove the old symlink in case the source has moved 112 operatorSymlink := "docs/content/docs/operator" 113 err := os.RemoveAll(operatorSymlink) 114 if !os.IsNotExist(err) { 115 mgx.Must(err) 116 } 117 118 repoPath := ensureOperatorRepository() 119 contentPath, _ := filepath.Abs("docs/content/docs") 120 relPath, _ := filepath.Rel(contentPath, filepath.Join(repoPath, "docs/content")) 121 log.Println("ln -s", relPath, operatorSymlink) 122 mgx.Must(os.Symlink(relPath, operatorSymlink)) 123 } 124 125 // Ensures that we have an operator repository and returns its location 126 func ensureOperatorRepository() string { 127 repoPath, err := ensureOperatorRepositoryIn(os.Getenv(LocalOperatorRepositoryEnv), DefaultOperatorSourceDir) 128 mgx.Must(err) 129 return repoPath 130 } 131 132 // Checks if the repository in localRepo exists and return it 133 // otherwise clone the repository into defaultRepo, updating with the latest changes if already cloned. 134 func ensureOperatorRepositoryIn(localRepo string, defaultRepo string) (string, error) { 135 // Check if we are using a local repo 136 if localRepo != "" { 137 if _, err := os.Stat(localRepo); err != nil { 138 log.Printf("%s %s does not exist, ignoring\n", LocalOperatorRepositoryEnv, localRepo) 139 os.Unsetenv(LocalOperatorRepositoryEnv) 140 } else { 141 log.Printf("Using operator repository at %s\n", localRepo) 142 return localRepo, nil 143 } 144 } 145 146 // Clone the repo, and ensure it is up-to-date 147 cloneDestination, _ := filepath.Abs(defaultRepo) 148 _, err := os.Stat(filepath.Join(cloneDestination, ".git")) 149 if err != nil && !os.IsNotExist(err) { 150 return "", err 151 } else if err == nil { 152 log.Println("Operator repository already cloned, updating") 153 if err = shx.Command("git", "fetch").In(cloneDestination).Run(); err != nil { 154 return "", err 155 } 156 if err = shx.Command("git", "reset", "--hard", "FETCH_HEAD").In(cloneDestination).Run(); err != nil { 157 return "", err 158 } 159 return cloneDestination, nil 160 } 161 162 log.Println("Cloning operator repository") 163 os.RemoveAll(cloneDestination) // if the path existed but wasn't a git repo, we want to remove it and start fresh 164 if err = shx.Run("git", "clone", "https://github.com/getporter/operator.git", cloneDestination); err != nil { 165 return "", err 166 } 167 return cloneDestination, nil 168 }