chore: work save
This commit is contained in:
parent
3e3f13d36d
commit
9752d63f7e
19 changed files with 1003 additions and 209 deletions
17
cmd/cmd/buildCmd.go
Normal file
17
cmd/cmd/buildCmd.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/tools"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewBuildCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "build",
|
||||
Short: "Build the necessary boilerplate",
|
||||
Long: `...`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return tools.Build()
|
||||
},
|
||||
}
|
||||
}
|
||||
498
cmd/cmd/publishCmd.go
Normal file
498
cmd/cmd/publishCmd.go
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
namespace string
|
||||
domain string
|
||||
providerName string
|
||||
distPath string
|
||||
repoName string
|
||||
version string
|
||||
gpgFingerprint string
|
||||
gpgPubKeyFile string
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "publish",
|
||||
Short: "Publish terraform provider",
|
||||
Long: `...`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return publish()
|
||||
},
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
rootCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&domain, "domain", "d", "", "Domain for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&providerName, "providerName", "p", "", "ProviderName for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&distPath, "distPath", "x", "dist", "Dist Path for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&repoName, "repoName", "r", "", "RepoName for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&version, "version", "v", "", "Version for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&gpgFingerprint, "gpgFingerprint", "f", "", "GPG Fingerprint for the Terraform registry.")
|
||||
rootCmd.Flags().StringVarP(&gpgPubKeyFile, "gpgPubKeyFile", "k", "", "GPG PubKey file name for the Terraform registry.")
|
||||
|
||||
err := rootCmd.MarkFlagRequired("namespace")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("domain")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("providerName")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("gpgFingerprint")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("gpgPubKeyFile")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("repoName")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("version")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("gpgFingerprint")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = rootCmd.MarkFlagRequired("gpgPubKeyFile")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func NewPublishCmd() *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func publish() error {
|
||||
log.Println("📦 Packaging Terraform Provider for private registry...")
|
||||
|
||||
distPath = filepath.Clean(distPath) + "/"
|
||||
|
||||
// Create release dir - only the contents of this need to be uploaded to S3
|
||||
err := createDir("release")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating 'release' dir: %s", err)
|
||||
}
|
||||
|
||||
// Create .wellKnown directory and terraform.json file
|
||||
err = wellKnown()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating '.wellKnown' dir: %s", err)
|
||||
}
|
||||
|
||||
// Create v1 directory
|
||||
err = provider(namespace, providerName, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating 'v1' dir: %s", err)
|
||||
}
|
||||
|
||||
log.Println("📦 Packaged Terraform Provider for private registry.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// This establishes the "API" as a TF provider by responding with the correct JSON payload, by using static files
|
||||
func wellKnown() error {
|
||||
log.Println("* Creating .well-known directory")
|
||||
|
||||
err := createDir("release/.well-known")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
terraformJson := []byte(`{"providers.v1": "/v1/providers/"}`)
|
||||
|
||||
log.Println(" - Writing to .well-known/terraform.json file")
|
||||
err = writeFile("release/.well-known/terraform.json", terraformJson)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// provider is the Terraform name
|
||||
// repoName is the Repository name
|
||||
func provider(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string) error {
|
||||
// Path to semantic version dir
|
||||
versionPath := providerDirs(namespace, provider, version)
|
||||
|
||||
// Files to create under v1/providers/[namespace]/[provider_name]
|
||||
err := createVersionsFile(namespace, provider, distPath, repoName, version)
|
||||
if err != nil {
|
||||
return err
|
||||
} // Creates version file one above download, which is why downloadPath isn't used
|
||||
|
||||
// Files/Directories to create under v1/providers/[namespace]/[provider_name]/[version]
|
||||
copyShaFiles(versionPath, distPath, repoName, version)
|
||||
downloadPath, err := createDownloadsDir(versionPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create darwin, freebsd, linux, windows dirs
|
||||
err = createTargetDirs(*downloadPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy all zips
|
||||
err = copyBuildZips(*downloadPath, distPath, repoName, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create all individual files for build targets and each architecture for the build targets
|
||||
err = createArchitectureFiles(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create the directories with a path format v1/providers/[namespace]/[provider_name]/[version]
|
||||
func providerDirs(namespace, repoName, version string) string {
|
||||
log.Println("* Creating release/v1/providers/[namespace]/[repo]/[version] directories")
|
||||
|
||||
providerPathArr := [6]string{"release", "v1", "providers", namespace, repoName, version}
|
||||
|
||||
var currentPath string
|
||||
for _, v := range providerPathArr {
|
||||
currentPath = currentPath + v + "/"
|
||||
err := createDir(currentPath)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return currentPath
|
||||
}
|
||||
|
||||
// Create the versions file under v1/providers/[namespace]/[provider_name]
|
||||
func createVersionsFile(namespace, provider, distPath, repoName, version string) error {
|
||||
log.Println("* Writing to release/v1/providers/[namespace]/[repo]/versions file")
|
||||
|
||||
versionPath := fmt.Sprintf("release/v1/providers/%s/%s/versions", namespace, provider)
|
||||
|
||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build the versions file...
|
||||
platforms := ""
|
||||
for _, line := range shaSumContents {
|
||||
fileName := line[1] // zip file name
|
||||
|
||||
// get os and arch from filename
|
||||
removeFileExtension := strings.Split(fileName, ".zip")
|
||||
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
||||
|
||||
// Get build target and architecture from the zip file name
|
||||
target := fileNameSplit[2]
|
||||
arch := fileNameSplit[3]
|
||||
|
||||
platforms += "{"
|
||||
platforms += fmt.Sprintf(`"os": "%s",`, target)
|
||||
platforms += fmt.Sprintf(`"arch": "%s"`, arch)
|
||||
platforms += "}"
|
||||
platforms += ","
|
||||
}
|
||||
platforms = strings.TrimRight(platforms, ",") // remove trailing comma, json does not allow
|
||||
|
||||
var versions = []byte(fmt.Sprintf(`
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"version": "%s",
|
||||
"protocols": [
|
||||
"4.0",
|
||||
"5.1",
|
||||
"6.0"
|
||||
],
|
||||
"platform": [
|
||||
%s
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
`, version, platforms))
|
||||
|
||||
err = writeFile(versionPath, versions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyShaFiles(destPath, srcPath, repoName, version string) {
|
||||
log.Printf("* Copying SHA files in %s directory", srcPath)
|
||||
|
||||
// Copy files from srcPath
|
||||
shaSum := repoName + "_" + version + "_SHA256SUMS"
|
||||
shaSumPath := srcPath + "/" + shaSum
|
||||
|
||||
// _SHA256SUMS file
|
||||
_, err := copyFile(shaSumPath, destPath+shaSum)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
// _SHA256SUMS.sig file
|
||||
_, err = copyFile(shaSumPath+".sig", destPath+shaSum+".sig")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func createDownloadsDir(destPath string) (*string, error) {
|
||||
log.Printf("* Creating download/ in %s directory", destPath)
|
||||
|
||||
downloadPath := path.Join(destPath, "download")
|
||||
|
||||
err := createDir(downloadPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &downloadPath, nil
|
||||
}
|
||||
|
||||
func createTargetDirs(destPath string) error {
|
||||
log.Printf("* Creating target dirs in %s directory", destPath)
|
||||
|
||||
targets := [4]string{"darwin", "freebsd", "linux", "windows"}
|
||||
|
||||
for _, v := range targets {
|
||||
err := createDir(destPath + v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyBuildZips(destPath, distPath, repoName, version string) error {
|
||||
log.Println("* Copying build zips")
|
||||
|
||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Loop through and copy each
|
||||
for _, v := range shaSumContents {
|
||||
zipName := v[1]
|
||||
zipSrcPath := distPath + zipName
|
||||
zipDestPath := destPath + zipName
|
||||
|
||||
log.Printf(" - Zip Source: %s", zipSrcPath)
|
||||
log.Printf(" - Zip Dest: %s", zipDestPath)
|
||||
|
||||
// Copy the zip
|
||||
_, err := copyFile(zipSrcPath, zipDestPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getShaSumContents(distPath, repoName, version string) ([][]string, error) {
|
||||
shaSumFileName := repoName + "_" + version + "_SHA256SUMS"
|
||||
shaSumPath := distPath + "/" + shaSumFileName
|
||||
|
||||
shaSumLine, err := readFile(shaSumPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buildsAndShaSums := [][]string{}
|
||||
|
||||
for _, line := range shaSumLine {
|
||||
lineSplit := strings.Split(line, " ")
|
||||
|
||||
row := []string{lineSplit[0], lineSplit[1]}
|
||||
buildsAndShaSums = append(buildsAndShaSums, row)
|
||||
}
|
||||
|
||||
// log.Println(buildsAndShaSums)
|
||||
|
||||
return buildsAndShaSums, nil
|
||||
}
|
||||
|
||||
// Create architecture files for each build target
|
||||
func createArchitectureFiles(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string) error {
|
||||
log.Println("* Creating architecture files in target directories")
|
||||
|
||||
// filename = terraform-provider-[provider]_0.0.1_darwin_amd64.zip - provider_name + version + target + architecture + .zip
|
||||
prefix := fmt.Sprintf("v1/providers/%s/%s/%s/", namespace, provider, version)
|
||||
pathPrefix := fmt.Sprintf("release/%s", prefix)
|
||||
urlPrefix := fmt.Sprintf("https://%s/%s", domain, prefix)
|
||||
|
||||
// download url = https://example.com/v1/providers/namespace/provider/0.0.1/download/terraform-provider_0.0.1_darwin_amd64.zip
|
||||
downloadUrlPrefix := urlPrefix + "download/"
|
||||
downloadPathPrefix := pathPrefix + "download/"
|
||||
|
||||
// shasums url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS
|
||||
shasumsUrl := urlPrefix + fmt.Sprintf("%s_%s_SHA256SUMS", repoName, version)
|
||||
// shasums_signature_url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS.sig
|
||||
shasumsSigUrl := shasumsUrl + ".sig"
|
||||
|
||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get contents of GPG key
|
||||
gpgFile, err := readFile(gpgPubKeyFile)
|
||||
if err != nil {
|
||||
log.Printf("Error reading '%s' file: %s", gpgPubKeyFile, err)
|
||||
}
|
||||
|
||||
// loop through every line and stick with \\n
|
||||
gpgAsciiPub := ""
|
||||
for _, line := range gpgFile {
|
||||
gpgAsciiPub = gpgAsciiPub + line + "\\n"
|
||||
}
|
||||
// log.Println(gpgAsciiPub)
|
||||
|
||||
for _, line := range shaSumContents {
|
||||
shasum := line[0] // shasum of the zip
|
||||
fileName := line[1] // zip file name
|
||||
|
||||
downloadUrl := downloadUrlPrefix + fileName
|
||||
|
||||
// get os and arch from filename
|
||||
removeFileExtension := strings.Split(fileName, ".zip")
|
||||
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
||||
|
||||
// Get build target and architecture from the zip file name
|
||||
target := fileNameSplit[2]
|
||||
arch := fileNameSplit[3]
|
||||
|
||||
// build filepath
|
||||
archFileName := downloadPathPrefix + target + "/" + arch
|
||||
|
||||
var architectureTemplate = []byte(fmt.Sprintf(`
|
||||
{
|
||||
"protocols": [
|
||||
"4.0",
|
||||
"5.1"
|
||||
],
|
||||
"os": "%s",
|
||||
"arch": "%s",
|
||||
"filename": "%s",
|
||||
"download_url": "%s",
|
||||
"shasums_url": "%s",
|
||||
"shasums_signature_url": "%s",
|
||||
"shasum": "%s",
|
||||
"signing_keys": {
|
||||
"gpg_public_keys": [
|
||||
{
|
||||
"key_id": "%s",
|
||||
"ascii_armor": "%s",
|
||||
"trust_signature": "",
|
||||
"source": "",
|
||||
"source_url": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`, target, arch, fileName, downloadUrl, shasumsUrl, shasumsSigUrl, shasum, gpgFingerprint, gpgAsciiPub))
|
||||
|
||||
log.Printf(" - Arch file: %s", archFileName)
|
||||
|
||||
err := writeFile(archFileName, architectureTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDir(path string) error {
|
||||
log.Printf("* Creating %s directory", path)
|
||||
err := os.Mkdir(path, os.ModePerm)
|
||||
if errors.Is(err, fs.ErrExist) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer destination.Close()
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
func readFile(filePath string) ([]string, error) {
|
||||
rFile, err := os.Open(filePath)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileScanner := bufio.NewScanner(rFile)
|
||||
fileScanner.Split(bufio.ScanLines)
|
||||
var fileLines []string
|
||||
|
||||
for fileScanner.Scan() {
|
||||
fileLines = append(fileLines, fileScanner.Text())
|
||||
}
|
||||
|
||||
rFile.Close()
|
||||
|
||||
return fileLines, nil
|
||||
}
|
||||
|
||||
func writeFile(fileName string, fileContents []byte) error {
|
||||
err := os.WriteFile(fileName, fileContents, 0644)
|
||||
return err
|
||||
}
|
||||
23
cmd/cmd/rootCmd.go
Normal file
23
cmd/cmd/rootCmd.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewRootCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "build-tools",
|
||||
Short: "...",
|
||||
Long: "...",
|
||||
SilenceErrors: true, // Error is beautified in a custom way before being printed
|
||||
SilenceUsage: true,
|
||||
DisableAutoGenTag: true,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
err := cmd.Help()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
34
cmd/main.go
34
cmd/main.go
|
|
@ -4,29 +4,23 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/tools"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/mhenselin/terraform-provider-stackitprivatepreview/cmd/cmd"
|
||||
)
|
||||
|
||||
func NewRootCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "builder",
|
||||
Short: "...",
|
||||
Long: "...",
|
||||
SilenceErrors: true, // Error is beautified in a custom way before being printed
|
||||
SilenceUsage: true,
|
||||
DisableAutoGenTag: true,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
return tools.Build()
|
||||
},
|
||||
}
|
||||
cmd.SetOut(os.Stdout)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmd := NewRootCmd()
|
||||
err := cmd.Execute()
|
||||
rootCmd := cmd.NewRootCmd()
|
||||
//rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
|
||||
//rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
|
||||
//rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
|
||||
|
||||
rootCmd.SetOut(os.Stdout)
|
||||
|
||||
rootCmd.AddCommand(
|
||||
cmd.NewBuildCmd(),
|
||||
cmd.NewPublishCmd(),
|
||||
)
|
||||
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue