@codedependant/semantic-release-docker 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/LICENSE +21 -0
  3. package/README.md +184 -0
  4. package/index.js +28 -0
  5. package/lib/build-config.js +63 -0
  6. package/lib/build-template-vars.js +28 -0
  7. package/lib/docker/image.js +127 -0
  8. package/lib/docker/index.js +5 -0
  9. package/lib/lang/array/index.js +5 -0
  10. package/lib/lang/array/to-array.js +9 -0
  11. package/lib/lang/object/get.js +18 -0
  12. package/lib/lang/object/has.js +8 -0
  13. package/lib/lang/object/index.js +6 -0
  14. package/lib/lang/string/index.js +5 -0
  15. package/lib/lang/string/template.js +14 -0
  16. package/lib/parse-pkg-name.js +12 -0
  17. package/lib/prepare.js +34 -0
  18. package/lib/publish.js +32 -0
  19. package/lib/read-pkg.js +12 -0
  20. package/lib/verify.js +95 -0
  21. package/package.json +98 -0
  22. package/test/common/git/add.js +9 -0
  23. package/test/common/git/commit.js +11 -0
  24. package/test/common/git/head.js +10 -0
  25. package/test/common/git/index.js +13 -0
  26. package/test/common/git/init-origin.js +13 -0
  27. package/test/common/git/init-remote.js +16 -0
  28. package/test/common/git/init.js +20 -0
  29. package/test/common/git/push.js +9 -0
  30. package/test/common/git/tag.js +13 -0
  31. package/test/common/git/tags.js +14 -0
  32. package/test/fixture/docker/Dockerfile.prepare +4 -0
  33. package/test/fixture/docker/Dockerfile.publish +4 -0
  34. package/test/fixture/docker/Dockerfile.test +4 -0
  35. package/test/fixture/package.json +4 -0
  36. package/test/fixture/pkg/one/package.json +5 -0
  37. package/test/fixture/pkg/two/package.json +0 -0
  38. package/test/integration/prepare.js +74 -0
  39. package/test/integration/publish.js +60 -0
  40. package/test/integration/release.js +92 -0
  41. package/test/integration/verify.js +205 -0
  42. package/test/unit/build-config.js +167 -0
  43. package/test/unit/build-template-vars.js +63 -0
  44. package/test/unit/docker/image.js +289 -0
  45. package/test/unit/lang/array.js +34 -0
  46. package/test/unit/lang/object.js +45 -0
  47. package/test/unit/lang/string.js +37 -0
  48. package/test/unit/parse-pkg-name.js +27 -0
  49. package/test/unit/read-pkg.js +36 -0
package/lib/publish.js ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ const buildTemplateVars = require('./build-template-vars.js')
4
+ const docker = require('./docker/index.js')
5
+ const string = require('./lang/string/index.js')
6
+
7
+ module.exports = publish
8
+
9
+ async function publish(opts, context) {
10
+ const {cwd, logger} = context
11
+ const image = new docker.Image({
12
+ registry: opts.registry
13
+ , project: opts.project
14
+ , name: opts.name
15
+ , dockerfile: opts.dockerfile
16
+ , build_id: opts.build
17
+ , cwd: cwd
18
+ })
19
+
20
+ const vars = buildTemplateVars(opts, context)
21
+ const tags = opts.tags.map((template) => {
22
+ return string.template(template)(vars)
23
+ }).filter(Boolean)
24
+
25
+ logger.info('tagging docker image', image.id)
26
+ for (const tag of tags) {
27
+ logger.info(`pushing image: ${image.repo} tag: ${tag}`)
28
+ await image.tag(tag, opts.publish)
29
+ }
30
+
31
+ await image.clean()
32
+ }
@@ -0,0 +1,12 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+ const {promises: fs} = require('fs')
5
+
6
+ module.exports = getPkg
7
+
8
+ async function getPkg(opts) {
9
+ const {cwd = process.cwd()} = opts || {}
10
+ const pkg = await fs.readFile(path.join(cwd, 'package.json'), 'utf8')
11
+ return JSON.parse(pkg)
12
+ }
package/lib/verify.js ADDED
@@ -0,0 +1,95 @@
1
+ 'use strict'
2
+
3
+ const {promises: fs} = require('fs')
4
+ const execa = require('execa')
5
+ const debug = require('debug')('semantic-release:semantic-release-docker:verify')
6
+ const SemanticError = require('@semantic-release/error')
7
+ const docker = require('./docker/index.js')
8
+
9
+ module.exports = verify
10
+
11
+ async function verify(opts, context) {
12
+ const {env, logger, cwd} = context
13
+ const PASSWORD = env.DOCKER_REGISTRY_PASSWORD || env.GITHUB_TOKEN
14
+ const USERNAME = env.DOCKER_REGISTRY_USER
15
+
16
+ if (!opts.name) {
17
+ const error = new SemanticError(
18
+ 'Docker image name not found'
19
+ , 'EINVAL'
20
+ , 'Image name parsed from package.json name if possible. Or via the "image" option.'
21
+ )
22
+ throw error
23
+ }
24
+
25
+ const image = new docker.Image({
26
+ registry: opts.registry
27
+ , project: opts.project
28
+ , name: opts.name
29
+ , dockerfile: opts.dockerfile
30
+ , build_id: opts.build
31
+ , cwd: cwd
32
+ })
33
+
34
+ debug('docker options', opts)
35
+
36
+ try {
37
+ await fs.readFile(image.dockerfile)
38
+ } catch (err) {
39
+ const error = new SemanticError(
40
+ `Unable to locate Dockerfile: ${image.dockerfile}`
41
+ , err.code
42
+ , 'Docker file is read from a local relative to PWD. Make sure the "dockerfile"'
43
+ + ' option is set to the desired location'
44
+ )
45
+
46
+ throw error
47
+ }
48
+
49
+ debug('image to build', image.repo)
50
+ if (!USERNAME && !PASSWORD) {
51
+ debug('No docker credentials found. Skipping login')
52
+ return false
53
+ }
54
+
55
+ if (opts.login === false) {
56
+ debug('docker login === false. Skipping login')
57
+ return false
58
+ }
59
+
60
+ let set = 0
61
+ if (USERNAME) set += 1
62
+ if (PASSWORD) set += 1
63
+
64
+ if (set !== 2) {
65
+ const error = new SemanticError(
66
+ 'Docker authentication failed'
67
+ , 'EAUTH'
68
+ , 'Both ENV vars DOCKER_REGISTRY_USER and DOCKER_REGISTRY_PASSWORD must be set'
69
+ )
70
+ throw error
71
+ }
72
+
73
+ const passwd = execa('echo', [PASSWORD])
74
+ const login = execa('docker', [
75
+ 'login'
76
+ , opts.registry || ''
77
+ , '-u', USERNAME
78
+ , '--password-stdin'
79
+ ])
80
+
81
+ passwd.stdout.pipe(login.stdin)
82
+
83
+ try {
84
+ await login
85
+ } catch (err) {
86
+ const error = new SemanticError(
87
+ 'Docker authentication failed'
88
+ , 'EAUTH'
89
+ , `Authentication to ${opts.registry || 'dockerhub'} failed`
90
+ )
91
+ throw error
92
+ }
93
+ logger.success('docker login successful')
94
+ return true
95
+ }
package/package.json ADDED
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "@codedependant/semantic-release-docker",
3
+ "private": false,
4
+ "version": "3.1.1",
5
+ "description": "docker package",
6
+ "main": "index.js",
7
+ "scripts": {
8
+ "test": "docker-compose -f compose/base.yml -f compose/test.yml up --exit-code-from semantic-release --force-recreate --remove-orphans",
9
+ "start": "docker-compose -f compose/base.yml -f compose/dev.yml up --force-recreate --remove-orphans --build",
10
+ "stop": "docker-compose -f compose/base.yml -f compose/dev.yml down",
11
+ "tap": "tap",
12
+ "lint": "eslint .",
13
+ "lint:fix": "npm run lint -- --fix",
14
+ "pretap": "npm run lint",
15
+ "release": "semantic-release"
16
+ },
17
+ "keywords": [
18
+ "semantic-release"
19
+ ],
20
+ "author": "Eric Satterwhite <esatterwhite@wi.rr.com>",
21
+ "license": "MIT",
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+ssh://git@github.com/esatterwhite/semantic-release-docker.git"
28
+ },
29
+ "eslintConfig": {
30
+ "root": true,
31
+ "extends": "codedependant",
32
+ "ignorePatterns": [
33
+ "node_modules/",
34
+ "test/fixture/",
35
+ "coverage/",
36
+ ".nyc_output/",
37
+ "env/",
38
+ "doc/"
39
+ ],
40
+ "rules": {
41
+ "object-shorthand": 0,
42
+ "no-unused-vars": [
43
+ "error",
44
+ {
45
+ "varsIgnorePattern": "_"
46
+ }
47
+ ],
48
+ "quote-props": [
49
+ 2,
50
+ "as-needed"
51
+ ]
52
+ }
53
+ },
54
+ "tap": {
55
+ "esm": false,
56
+ "ts": false,
57
+ "jsx": false,
58
+ "timeout": 60,
59
+ "browser": false,
60
+ "check-coverage": true,
61
+ "lines": 95,
62
+ "branches": 95,
63
+ "statements": 95,
64
+ "functions": 95,
65
+ "files": [
66
+ "test/unit",
67
+ "test/integration"
68
+ ],
69
+ "coverage-report": [
70
+ "text",
71
+ "text-summary",
72
+ "json",
73
+ "html"
74
+ ],
75
+ "nyc-arg": [
76
+ "--exclude=coverage/",
77
+ "--exclude=test/",
78
+ "--all"
79
+ ]
80
+ },
81
+ "devDependencies": {
82
+ "@codedependant/release-config-npm": "^1.0.1",
83
+ "@semantic-release/changelog": "^5.0.1",
84
+ "@semantic-release/git": "^9.0.0",
85
+ "@semantic-release/github": "^7.0.7",
86
+ "eslint": "^7.4.0",
87
+ "eslint-config-codedependant": "^2.1.6",
88
+ "sinon": "^9.0.2",
89
+ "tap": "^14.10.7"
90
+ },
91
+ "dependencies": {
92
+ "@semantic-release/error": "^2.2.0",
93
+ "debug": "^4.1.1",
94
+ "execa": "^4.0.2",
95
+ "semantic-release": "^17.1.1",
96
+ "semver": "^7.3.2"
97
+ }
98
+ }
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+
5
+ module.exports = add
6
+
7
+ async function add(cwd, file = '.') {
8
+ await execa('git', ['add', file], {cwd: cwd})
9
+ }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+ const head = require('./head.js')
5
+
6
+ module.exports = commit
7
+
8
+ async function commit(cwd, message) {
9
+ await execa('git', ['commit', '-m', message], {cwd: cwd})
10
+ return head(cwd)
11
+ }
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+
5
+ module.exports = head
6
+
7
+ async function head(cwd) {
8
+ const {stdout} = await execa('git', ['rev-parse', 'HEAD'], {cwd: cwd})
9
+ return stdout
10
+ }
@@ -0,0 +1,13 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ add: require('./add.js')
5
+ , commit: require('./commit.js')
6
+ , head: require('./head.js')
7
+ , initOrigin: require('./init-origin.js')
8
+ , initRemote: require('./init-remote.js')
9
+ , init: require('./init.js')
10
+ , push: require('./push.js')
11
+ , tag: require('./tag.js')
12
+ , tags: require('./tags.js')
13
+ }
@@ -0,0 +1,13 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+ const initRemote = require('./init-remote.js')
5
+
6
+ module.exports = initOrigin
7
+
8
+ async function initOrigin(cwd) {
9
+ const origin = await initRemote()
10
+ await execa('git', ['remote', 'add', 'origin', origin], {cwd: cwd})
11
+ await execa('git', ['push', '--all', 'origin'], {cwd: cwd})
12
+ return origin
13
+ }
@@ -0,0 +1,16 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+ const os = require('os')
5
+ const {promises: fs} = require('fs')
6
+ const execa = require('execa')
7
+
8
+ module.exports = initRemote
9
+
10
+ async function initRemote(branch = 'main') {
11
+ const cwd = await fs.mkdtemp(path.join(os.tmpdir(), path.sep))
12
+ await execa('git', [
13
+ 'init', '--bare', `--initial-branch=${branch}`
14
+ ], {cwd: cwd})
15
+ return `file://${cwd}`
16
+ }
@@ -0,0 +1,20 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+ const os = require('os')
5
+ const {promises: fs} = require('fs')
6
+ const execa = require('execa')
7
+
8
+ module.exports = init
9
+
10
+ async function init(dir, branch = 'main') {
11
+ const cwd = dir || await fs.mkdtemp(path.join(os.tmpdir(), path.sep))
12
+ await execa('git', ['init', cwd])
13
+ await execa('git', ['checkout', '-b', branch], {cwd: cwd})
14
+ await execa('git', ['config', '--add', 'commit.gpgsign', false])
15
+ await execa('git', ['config', '--add', 'pull.default', 'current'], {cwd})
16
+ await execa('git', ['config', '--add', 'push.default', 'current'], {cwd})
17
+ await execa('git', ['config', '--add', 'user.name', 'secretsquirrel'], {cwd})
18
+ await execa('git', ['config', '--add', 'user.email', 'secret@mail.com'], {cwd})
19
+ return cwd
20
+ }
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+
5
+ module.exports = push
6
+
7
+ async function push(cwd, remote = 'origin', branch = 'main') {
8
+ await execa('git', ['push', '--tags', remote, `HEAD:${branch}`], {cwd: cwd})
9
+ }
@@ -0,0 +1,13 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+
5
+ module.exports = tag
6
+
7
+ async function tag(cwd, name, hash) {
8
+ const args = hash
9
+ ? ['tag', '-f', name, hash]
10
+ : ['tag', name]
11
+
12
+ await execa('git', args, {cwd: cwd})
13
+ }
@@ -0,0 +1,14 @@
1
+ 'use strict'
2
+
3
+ const os = require('os')
4
+ const execa = require('execa')
5
+
6
+ module.exports = tags
7
+
8
+ async function tags(cwd, hash) {
9
+ const cmd = hash
10
+ ? ['describe', '--tags', '--exact-match', hash]
11
+ : ['tag', '-l', '--sort', 'v:refname']
12
+ const {stdout} = await execa('git', cmd, {cwd: cwd})
13
+ return stdout.split(os.EOL).filter(Boolean)
14
+ }
@@ -0,0 +1,4 @@
1
+ FROM debian:buster-slim
2
+ COPY . /opt/prepare
3
+ WORKDIR /opt/prepare
4
+ CMD ["echo", "$PWD"]
@@ -0,0 +1,4 @@
1
+ FROM debian:buster-slim
2
+ COPY . /opt/whizbang
3
+ WORKDIR /opt/whizbang
4
+ CMD ["echo", "$PWD"]
@@ -0,0 +1,4 @@
1
+ FROM debian:buster-slim
2
+ COPY . /opt/app
3
+ WORKDIR /opt/app
4
+ RUN ls -alh
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "@fake-scope/whizbangs"
3
+ , "version": "0.0.0"
4
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@fixture/one",
3
+ "version": "0.0.0",
4
+ "private": true
5
+ }
File without changes
@@ -0,0 +1,74 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+ const crypto = require('crypto')
5
+ const sinon = require('sinon')
6
+ const execa = require('execa')
7
+ const {test, threw} = require('tap')
8
+ const buildConfig = require('../../lib/build-config.js')
9
+ const verify = require('../../lib/verify.js')
10
+ const prepare = require('../../lib/prepare.js')
11
+ const DOCKER_REGISTRY_HOST = process.env.TEST_DOCKER_REGISTRY || 'localhost:5000'
12
+ const fixturedir = path.join(__dirname, '..', 'fixture')
13
+ const DATE_REGEX = new RegExp(
14
+ '^[\\d]{4}-[\\d]{2}-[\\d]{2}T[\\d]{2}:[\\d]{2}:[\\d]{2}'
15
+ + '(\.[\\d]{1,6})?(Z|[\\+\\-][\\d]{2}:[\\d]{2})$' // eslint-disable-line no-useless-escape
16
+ )
17
+
18
+ test('steps::prepare', async (t) => {
19
+ t.test('build image created', async (tt) => {
20
+ const build_id = crypto.randomBytes(5).toString('hex')
21
+ const context = {
22
+ env: {
23
+ ...process.env
24
+ , DOCKER_REGISTRY_USER: 'iamweasel'
25
+ , DOCKER_REGISTRY_PASSWORD: 'secretsquirrel'
26
+ }
27
+ , cwd: fixturedir
28
+ , nextRelease: {
29
+ version: '2.1.2'
30
+ , gitTag: 'v2.1.2'
31
+ , gitHead: 'abacadaba'
32
+ }
33
+ , logger: {
34
+ success: sinon.stub()
35
+ , info: sinon.stub()
36
+ , debug: sinon.stub()
37
+ }
38
+ }
39
+
40
+ const config = await buildConfig(build_id, {
41
+ dockerRegistry: DOCKER_REGISTRY_HOST
42
+ , dockerProject: 'docker-prepare'
43
+ , dockerImage: 'fake'
44
+ , dockerArgs: {
45
+ MY_VARIABLE: '1'
46
+ , TAG_TEMPLATE: '{git_tag}'
47
+ , MAJOR_TEMPLATE: '{major}'
48
+ , GIT_REF: '{git_sha}'
49
+ , BUILD_DATE: '{now}'
50
+ }
51
+ , dockerFile: 'docker/Dockerfile.prepare'
52
+ }, context)
53
+
54
+ const auth = await verify(config, context)
55
+ tt.ok(auth, `authentication to ${DOCKER_REGISTRY_HOST} suceeds`)
56
+
57
+ const image = await prepare(config, context)
58
+
59
+ tt.on('end', () => {
60
+ image.clean()
61
+ })
62
+
63
+ tt.equal(image.opts.args.get('TAG_TEMPLATE'), 'v2.1.2', 'TAG_TEMPLATE value')
64
+ tt.equal(image.opts.args.get('MAJOR_TEMPLATE'), '2', 'MAJOR_TEMPLATE value')
65
+ tt.equal(image.opts.args.get('GIT_REF'), 'abacadaba', 'GIT_REF value')
66
+ tt.match(image.opts.args.get('BUILD_DATE'), DATE_REGEX, 'BUILD_DATE value')
67
+
68
+ const {stdout} = await execa('docker', [
69
+ 'images', image.name
70
+ , '-q', '--format={{ .Tag }}'
71
+ ])
72
+ tt.equal(stdout, build_id, 'build image fully built')
73
+ })
74
+ }).catch(threw)
@@ -0,0 +1,60 @@
1
+ 'use strict'
2
+
3
+ const crypto = require('crypto')
4
+ const path = require('path')
5
+ const sinon = require('sinon')
6
+ const execa = require('execa')
7
+ const {test, threw} = require('tap')
8
+ const buildConfig = require('../../lib/build-config.js')
9
+ const verify = require('../../lib/verify.js')
10
+ const prepare = require('../../lib/prepare.js')
11
+ const publish = require('../../lib/publish.js')
12
+ const DOCKER_REGISTRY_HOST = process.env.TEST_DOCKER_REGISTRY || 'localhost:5000'
13
+ const fixturedir = path.join(__dirname, '..', 'fixture')
14
+
15
+ test('steps::publish', async (t) => {
16
+ t.test('publish multi tags', async (tt) => {
17
+ const build_id = crypto.randomBytes(5).toString('hex')
18
+ const context = {
19
+ env: {
20
+ ...process.env
21
+ , DOCKER_REGISTRY_USER: 'iamweasel'
22
+ , DOCKER_REGISTRY_PASSWORD: 'secretsquirrel'
23
+ }
24
+ , cwd: fixturedir
25
+ , nextRelease: {version: '2.0.0'}
26
+ , lastRelease: {version: '1.5.0'}
27
+ , logger: {
28
+ success: sinon.stub()
29
+ , info: sinon.stub()
30
+ , debug: sinon.stub()
31
+ }
32
+ }
33
+
34
+ const config = await buildConfig(build_id, {
35
+ dockerRegistry: DOCKER_REGISTRY_HOST
36
+ , dockerProject: 'docker-publish'
37
+ , dockerImage: 'real'
38
+ , dockerTags: ['{previous.major}-previous', '{major}-foobar', '{version}']
39
+ , dockerFile: 'docker/Dockerfile.publish'
40
+ }, context)
41
+
42
+ const auth = await verify(config, context)
43
+ tt.ok(auth, `authentication to ${DOCKER_REGISTRY_HOST} suceeds`)
44
+
45
+ const image = await prepare(config, context)
46
+ tt.on('end', () => {
47
+ image.clean()
48
+ })
49
+
50
+ // removes images when done
51
+ await publish(config, context)
52
+
53
+ const tags = ['1-previous', '2-foobar', '2.0.0']
54
+ for (const tag of tags) {
55
+ const expected = `${image.repo}:${tag}`
56
+ const {stdout} = await execa('docker', ['pull', expected, '-q'])
57
+ tt.equal(expected, stdout, `${expected} successfully published`)
58
+ }
59
+ })
60
+ }).catch(threw)
@@ -0,0 +1,92 @@
1
+ 'use strict'
2
+
3
+ const execa = require('execa')
4
+ const {test, threw} = require('tap')
5
+ const git = require('../common/git/index.js')
6
+ const DOCKER_REGISTRY_HOST = process.env.TEST_DOCKER_REGISTRY || 'localhost:5000'
7
+
8
+ const stringify = JSON.stringify
9
+
10
+ test('docker release', async (t) => {
11
+ const cwd = t.testdir({
12
+ 'package.json': stringify({
13
+ name: 'service-meta-package'
14
+ , version: '0.0.0-development'
15
+ , scripts: {
16
+ 'test-release': 'semantic-release'
17
+ }
18
+ , release: {
19
+ ci: true
20
+ , npmPublish: false
21
+ , branches: ['main']
22
+ , dockerRegistry: DOCKER_REGISTRY_HOST
23
+ , dockerProject: 'docker-release'
24
+ , dockerImage: 'fake'
25
+ , dockerArgs: {
26
+ SAMPLE_THING: '{type}.{version}'
27
+ , GIT_REF: '{git_sha}-{git_tag}'
28
+ , BUILD_DATE: '{now}'
29
+ }
30
+ , plugins: [
31
+ '@semantic-release/commit-analyzer'
32
+ , '@semantic-release/release-notes-generator'
33
+ , '@semantic-release/npm'
34
+ , '@codedependant/semantic-release-docker'
35
+ ]
36
+ }
37
+ , devDependencies: {
38
+ 'semantic-release': '*'
39
+ , '@semantic-release/commit-analyzer': '*'
40
+ , '@semantic-release/release-notes-generator': '*'
41
+ , '@semantic-release/npm': '*'
42
+ , '@codedependant/semantic-release-docker': 'file:../../../'
43
+ }
44
+ })
45
+ , Dockerfile: 'FROM debian:buster-slim\n\nRUN ls -alh'
46
+ , '.gitignore': 'node_modules/'
47
+ })
48
+
49
+ await git.init(cwd)
50
+ t.comment('git repo initialized')
51
+ await git.add(cwd)
52
+ await git.commit(cwd, 'feat: initial release')
53
+
54
+ const origin = await git.initOrigin(cwd)
55
+ t.comment(`repository: ${cwd}`)
56
+ t.comment(`origin: ${origin}`)
57
+
58
+ {
59
+ const stream = execa('npm', [
60
+ 'install'
61
+ ], {
62
+ cwd: cwd
63
+ , env: {
64
+ BRANCH_NAME: 'main'
65
+ , CI_BRANCH: 'main'
66
+ , CI: 'true'
67
+ , GITHUB_REF: 'refs/heads/main'
68
+ , DOCKER_REGISTRY_USER: 'iamweasel'
69
+ , DOCKER_REGISTRY_PASSWORD: 'secretsquirrel'
70
+ }
71
+ })
72
+
73
+ stream.stdout.pipe(process.stdout)
74
+ await stream
75
+ }
76
+
77
+ const stream = execa('npm', [
78
+ 'run'
79
+ , 'test-release'
80
+ , `--repositoryUrl=${origin}`], {
81
+ cwd: cwd
82
+ , env: {
83
+ BRANCH_NAME: 'main'
84
+ , CI_BRANCH: 'main'
85
+ , CI: 'true'
86
+ , GITHUB_REF: 'refs/heads/main'
87
+ }
88
+ })
89
+ stream.stdout.pipe(process.stdout)
90
+ await stream
91
+
92
+ }).catch(threw)