1package integration_test 2 3import ( 4 "fmt" 5 "path/filepath" 6 "regexp" 7 "strings" 8 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 12 . "github.com/cloudfoundry/bosh-cli/cmd" 13 14 boshlog "github.com/cloudfoundry/bosh-utils/logger" 15 boshsys "github.com/cloudfoundry/bosh-utils/system" 16 "github.com/cloudfoundry/bosh-utils/uuid" 17 18 "os" 19 20 boshrel "github.com/cloudfoundry/bosh-cli/release" 21 boshrelman "github.com/cloudfoundry/bosh-cli/release/manifest" 22 boshui "github.com/cloudfoundry/bosh-cli/ui" 23 fakeui "github.com/cloudfoundry/bosh-cli/ui/fakes" 24) 25 26var _ = Describe("create-release command", func() { 27 var ( 28 ui *fakeui.FakeUI 29 fs boshsys.FileSystem 30 deps BasicDeps 31 cmdFactory Factory 32 ) 33 34 BeforeEach(func() { 35 ui = &fakeui.FakeUI{} 36 logger := boshlog.NewLogger(boshlog.LevelNone) 37 confUI := boshui.NewWrappingConfUI(ui, logger) 38 39 fs = boshsys.NewOsFileSystem(logger) 40 deps = NewBasicDepsWithFS(confUI, fs, logger) 41 cmdFactory = NewFactory(deps) 42 }) 43 44 execCmd := func(args []string) { 45 cmd, err := cmdFactory.New(args) 46 Expect(err).ToNot(HaveOccurred()) 47 48 err = cmd.Execute() 49 Expect(err).ToNot(HaveOccurred()) 50 } 51 52 removeSHA256s := func(contents string) string { 53 matchSHA256s := regexp.MustCompile("sha1: sha256:[a-z0-9]{64}\n") 54 return matchSHA256s.ReplaceAllString(contents, "sha1: replaced\n") 55 } 56 57 expectSha256Checksums := func(filePath string) { 58 contents, err := fs.ReadFileString(filePath) 59 Expect(err).ToNot(HaveOccurred()) 60 Expect(contents).To(MatchRegexp("sha1: sha256:.*")) 61 } 62 63 It("can iterate on a basic release", func() { 64 suffix, err := uuid.NewGenerator().Generate() 65 Expect(err).ToNot(HaveOccurred()) 66 67 // containing the release in a directory that is a symlink 68 // to ensure we can work inside symlinks (i.e. macOS /tmp) 69 containerDir := filepath.Join("/", "tmp", suffix) 70 symlinkedContainerDir := fmt.Sprintf("%s-symlinked", containerDir) 71 fs.MkdirAll(containerDir, 0755) 72 fs.Symlink(containerDir, symlinkedContainerDir) 73 tmpDir := filepath.Join(symlinkedContainerDir, "release") 74 75 defer func() { 76 fs.RemoveAll(containerDir) 77 fs.RemoveAll(symlinkedContainerDir) 78 }() 79 80 relName := filepath.Base(tmpDir) 81 82 { 83 execCmd([]string{"init-release", "--dir", tmpDir}) 84 Expect(fs.FileExists(filepath.Join(tmpDir, "config"))).To(BeTrue()) 85 Expect(fs.FileExists(filepath.Join(tmpDir, "jobs"))).To(BeTrue()) 86 Expect(fs.FileExists(filepath.Join(tmpDir, "packages"))).To(BeTrue()) 87 Expect(fs.FileExists(filepath.Join(tmpDir, "src"))).To(BeTrue()) 88 } 89 90 execCmd([]string{"generate-job", "job1", "--dir", tmpDir}) 91 execCmd([]string{"generate-package", "pkg1", "--dir", tmpDir}) 92 execCmd([]string{"generate-package", "pkg2", "--dir", tmpDir}) 93 94 err = fs.WriteFileString(filepath.Join(tmpDir, "LICENSE"), "LICENSE") 95 Expect(err).ToNot(HaveOccurred()) 96 97 { // pkg1 depends on pkg2 for compilation 98 pkg1SpecPath := filepath.Join(tmpDir, "packages", "pkg1", "spec") 99 100 contents, err := fs.ReadFileString(pkg1SpecPath) 101 Expect(err).ToNot(HaveOccurred()) 102 103 err = fs.WriteFileString(pkg1SpecPath, strings.Replace(contents, "dependencies: []", "dependencies: [pkg2]", -1)) 104 Expect(err).ToNot(HaveOccurred()) 105 } 106 107 { // job1 depends on both packages 108 jobSpecPath := filepath.Join(tmpDir, "jobs", "job1", "spec") 109 110 contents, err := fs.ReadFileString(jobSpecPath) 111 Expect(err).ToNot(HaveOccurred()) 112 113 err = fs.WriteFileString(jobSpecPath, strings.Replace(contents, "packages: []", "packages: [pkg1, pkg2]", -1)) 114 Expect(err).ToNot(HaveOccurred()) 115 } 116 117 { // Make empty release 118 execCmd([]string{"create-release", "--dir", tmpDir}) 119 120 contents, err := fs.ReadFileString(filepath.Join(tmpDir, "dev_releases", relName, relName+"-0+dev.1.yml")) 121 Expect(err).ToNot(HaveOccurred()) 122 123 Expect(removeSHA256s(contents)).To(Equal( 124 "name: " + relName + ` 125version: 0+dev.1 126commit_hash: non-git 127uncommitted_changes: false 128jobs: 129- name: job1 130 version: f54520d6563c438bf0bc5bb674777db171b78d848a057a3faec0e9b572c3a76c 131 fingerprint: f54520d6563c438bf0bc5bb674777db171b78d848a057a3faec0e9b572c3a76c 132 sha1: replaced 133 packages: 134 - pkg1 135 - pkg2 136packages: 137- name: pkg1 138 version: 08441a1962e8141645edb0f2ddb91330454f2f1a3954d7f27fa256eb5e7b4ed6 139 fingerprint: 08441a1962e8141645edb0f2ddb91330454f2f1a3954d7f27fa256eb5e7b4ed6 140 sha1: replaced 141 dependencies: 142 - pkg2 143- name: pkg2 144 version: 34581dd0d93735e444a32450e3ae3951258c936479b45e08f1fa074740c7e392 145 fingerprint: 34581dd0d93735e444a32450e3ae3951258c936479b45e08f1fa074740c7e392 146 sha1: replaced 147 dependencies: [] 148license: 149 version: 42a33a7295936a632c8f54e70f2553975ee38a476d6aae93f3676e68c9db2f86 150 fingerprint: 42a33a7295936a632c8f54e70f2553975ee38a476d6aae93f3676e68c9db2f86 151 sha1: replaced 152`)) 153 } 154 155 { // Add a bit of content 156 err := fs.WriteFileString(filepath.Join(tmpDir, "src", "in-src"), "in-src") 157 Expect(err).ToNot(HaveOccurred()) 158 159 randomFile := filepath.Join(tmpDir, "random-file") 160 161 err = fs.WriteFileString(randomFile, "in-blobs") 162 Expect(err).ToNot(HaveOccurred()) 163 164 execCmd([]string{"add-blob", randomFile, "in-blobs", "--dir", tmpDir}) 165 166 pkg1SpecPath := filepath.Join(tmpDir, "packages", "pkg1", "spec") 167 168 contents, err := fs.ReadFileString(pkg1SpecPath) 169 Expect(err).ToNot(HaveOccurred()) 170 171 err = fs.WriteFileString(pkg1SpecPath, strings.Replace(contents, "files: []", "files:\n- in-src\n- in-blobs", -1)) 172 Expect(err).ToNot(HaveOccurred()) 173 } 174 175 { // Make release with some contents 176 execCmd([]string{"create-release", "--dir", tmpDir}) 177 178 rel1File := filepath.Join(tmpDir, "dev_releases", relName, relName+"-0+dev.1.yml") 179 rel2File := filepath.Join(tmpDir, "dev_releases", relName, relName+"-0+dev.2.yml") 180 181 contents, err := fs.ReadFileString(rel2File) 182 Expect(err).ToNot(HaveOccurred()) 183 184 Expect(removeSHA256s(contents)).To(Equal( 185 "name: " + relName + ` 186version: 0+dev.2 187commit_hash: non-git 188uncommitted_changes: false 189jobs: 190- name: job1 191 version: f54520d6563c438bf0bc5bb674777db171b78d848a057a3faec0e9b572c3a76c 192 fingerprint: f54520d6563c438bf0bc5bb674777db171b78d848a057a3faec0e9b572c3a76c 193 sha1: replaced 194 packages: 195 - pkg1 196 - pkg2 197packages: 198- name: pkg1 199 version: 00ebebd8dd5a533a91f9de34b0cf708772fca87ada7e37e63bec00ece2e0634c 200 fingerprint: 00ebebd8dd5a533a91f9de34b0cf708772fca87ada7e37e63bec00ece2e0634c 201 sha1: replaced 202 dependencies: 203 - pkg2 204- name: pkg2 205 version: 34581dd0d93735e444a32450e3ae3951258c936479b45e08f1fa074740c7e392 206 fingerprint: 34581dd0d93735e444a32450e3ae3951258c936479b45e08f1fa074740c7e392 207 sha1: replaced 208 dependencies: [] 209license: 210 version: 42a33a7295936a632c8f54e70f2553975ee38a476d6aae93f3676e68c9db2f86 211 fingerprint: 42a33a7295936a632c8f54e70f2553975ee38a476d6aae93f3676e68c9db2f86 212 sha1: replaced 213`, 214 )) 215 216 man1, err := boshrelman.NewManifestFromPath(rel1File, fs) 217 Expect(err).ToNot(HaveOccurred()) 218 219 man2, err := boshrelman.NewManifestFromPath(rel2File, fs) 220 Expect(err).ToNot(HaveOccurred()) 221 222 // Explicitly check that pkg1 changed its fingerprint 223 Expect(man1.Packages[0].Name).To(Equal(man2.Packages[0].Name)) 224 Expect(man1.Packages[0].Fingerprint).ToNot(Equal(man2.Packages[0].Fingerprint)) 225 226 // and pkg2 did not change 227 Expect(man1.Packages[1].Name).To(Equal(man2.Packages[1].Name)) 228 Expect(man1.Packages[1].Fingerprint).To(Equal(man2.Packages[1].Fingerprint)) 229 } 230 231 { // check contents of index files when sha2 flag is supplied 232 execCmd([]string{"create-release", "--sha2", "--dir", tmpDir}) 233 234 expectSha256Checksums(filepath.Join(tmpDir, "dev_releases", relName, relName+"-0+dev.3.yml")) 235 expectSha256Checksums(filepath.Join(tmpDir, ".dev_builds", "jobs", "job1", "index.yml")) 236 expectSha256Checksums(filepath.Join(tmpDir, ".dev_builds", "packages", "pkg1", "index.yml")) 237 expectSha256Checksums(filepath.Join(tmpDir, ".dev_builds", "license", "index.yml")) 238 } 239 240 { // Check contents of made release via its tarball 241 tgzFile := filepath.Join(tmpDir, "release-3.tgz") 242 243 execCmd([]string{"create-release", "--dir", tmpDir, "--tarball", tgzFile}) 244 relProvider := boshrel.NewProvider(deps.CmdRunner, deps.Compressor, deps.DigestCalculator, deps.FS, deps.Logger) 245 extractingArchiveReader := relProvider.NewExtractingArchiveReader() 246 247 extractingRelease, err := extractingArchiveReader.Read(tgzFile) 248 Expect(err).ToNot(HaveOccurred()) 249 250 defer extractingRelease.CleanUp() 251 252 pkg1 := extractingRelease.Packages()[0] 253 Expect(fs.ReadFileString(filepath.Join(pkg1.ExtractedPath(), "in-src"))).To(Equal("in-src")) 254 Expect(fs.ReadFileString(filepath.Join(pkg1.ExtractedPath(), "in-blobs"))).To(Equal("in-blobs")) 255 256 archiveReader := relProvider.NewArchiveReader() 257 258 release, err := archiveReader.Read(tgzFile) 259 Expect(err).ToNot(HaveOccurred()) 260 261 defer release.CleanUp() 262 263 job1 := release.Jobs()[0] 264 Expect(job1.PackageNames).To(ConsistOf("pkg1", "pkg2")) 265 } 266 267 { // Check that tarballs will not overwrite a directory 268 directoryPath := filepath.Join(tmpDir, "tarball-collision-dir") 269 Expect(fs.MkdirAll(directoryPath, os.ModeDir)).To(Succeed()) 270 _, err := cmdFactory.New([]string{"create-release", "--dir", tmpDir, "--tarball", directoryPath}) 271 Expect(err).To(HaveOccurred()) 272 Expect(err.Error()).To(ContainSubstring("Path must not be directory")) 273 } 274 275 { // removes unknown blobs, keeping known blobs 276 blobPath := filepath.Join(tmpDir, "blobs", "unknown-blob.tgz") 277 278 fs.WriteFileString(blobPath, "i don't belong here") 279 280 execCmd([]string{"create-release", "--dir", tmpDir}) 281 Expect(fs.FileExists(blobPath)).To(BeFalse()) 282 Expect(fs.FileExists(filepath.Join(tmpDir, "blobs", "in-blobs"))).To(BeTrue()) 283 } 284 }) 285}) 286