@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.
- package/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +184 -0
- package/index.js +28 -0
- package/lib/build-config.js +63 -0
- package/lib/build-template-vars.js +28 -0
- package/lib/docker/image.js +127 -0
- package/lib/docker/index.js +5 -0
- package/lib/lang/array/index.js +5 -0
- package/lib/lang/array/to-array.js +9 -0
- package/lib/lang/object/get.js +18 -0
- package/lib/lang/object/has.js +8 -0
- package/lib/lang/object/index.js +6 -0
- package/lib/lang/string/index.js +5 -0
- package/lib/lang/string/template.js +14 -0
- package/lib/parse-pkg-name.js +12 -0
- package/lib/prepare.js +34 -0
- package/lib/publish.js +32 -0
- package/lib/read-pkg.js +12 -0
- package/lib/verify.js +95 -0
- package/package.json +98 -0
- package/test/common/git/add.js +9 -0
- package/test/common/git/commit.js +11 -0
- package/test/common/git/head.js +10 -0
- package/test/common/git/index.js +13 -0
- package/test/common/git/init-origin.js +13 -0
- package/test/common/git/init-remote.js +16 -0
- package/test/common/git/init.js +20 -0
- package/test/common/git/push.js +9 -0
- package/test/common/git/tag.js +13 -0
- package/test/common/git/tags.js +14 -0
- package/test/fixture/docker/Dockerfile.prepare +4 -0
- package/test/fixture/docker/Dockerfile.publish +4 -0
- package/test/fixture/docker/Dockerfile.test +4 -0
- package/test/fixture/package.json +4 -0
- package/test/fixture/pkg/one/package.json +5 -0
- package/test/fixture/pkg/two/package.json +0 -0
- package/test/integration/prepare.js +74 -0
- package/test/integration/publish.js +60 -0
- package/test/integration/release.js +92 -0
- package/test/integration/verify.js +205 -0
- package/test/unit/build-config.js +167 -0
- package/test/unit/build-template-vars.js +63 -0
- package/test/unit/docker/image.js +289 -0
- package/test/unit/lang/array.js +34 -0
- package/test/unit/lang/object.js +45 -0
- package/test/unit/lang/string.js +37 -0
- package/test/unit/parse-pkg-name.js +27 -0
- package/test/unit/read-pkg.js +36 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto')
|
|
4
|
+
const sinon = require('sinon')
|
|
5
|
+
const {test, threw} = require('tap')
|
|
6
|
+
|
|
7
|
+
const buildConfig = require('../../lib/build-config.js')
|
|
8
|
+
const verify = require('../../lib/verify.js')
|
|
9
|
+
const DOCKER_REGISTRY_HOST = process.env.TEST_DOCKER_REGISTRY || 'localhost:5000'
|
|
10
|
+
|
|
11
|
+
test('steps::verify', async (t) => {
|
|
12
|
+
const build_id = crypto.randomBytes(5).toString('hex')
|
|
13
|
+
t.test('docker password, no username', async (tt) => {
|
|
14
|
+
const context = {
|
|
15
|
+
env: {
|
|
16
|
+
...process.env
|
|
17
|
+
, DOCKER_REGISTRY_PASSWORD: 'abc123'
|
|
18
|
+
}
|
|
19
|
+
, cwd: process.cwd()
|
|
20
|
+
, logger: {
|
|
21
|
+
success: sinon.stub()
|
|
22
|
+
, info: sinon.stub()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const config = await buildConfig(build_id, {}, context)
|
|
26
|
+
await tt.rejects(
|
|
27
|
+
verify(config, context)
|
|
28
|
+
, {
|
|
29
|
+
message: /docker authentication failed/i
|
|
30
|
+
, code: 'EAUTH'
|
|
31
|
+
, details: /DOCKER_REGISTRY_USER AND DOCKER_REGISTRY_PASSWORD must be set/ig
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
t.test('docker password, no username', async (tt) => {
|
|
37
|
+
const context = {
|
|
38
|
+
env: {
|
|
39
|
+
...process.env
|
|
40
|
+
, DOCKER_REGISTRY_USER: 'abc123'
|
|
41
|
+
}
|
|
42
|
+
, cwd: process.cwd()
|
|
43
|
+
, logger: {
|
|
44
|
+
success: sinon.stub()
|
|
45
|
+
, info: sinon.stub()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const config = await buildConfig(build_id, {}, context)
|
|
49
|
+
await tt.rejects(
|
|
50
|
+
verify(config, context)
|
|
51
|
+
, {
|
|
52
|
+
message: /docker authentication failed/i
|
|
53
|
+
, code: 'EAUTH'
|
|
54
|
+
, details: /DOCKER_REGISTRY_USER AND DOCKER_REGISTRY_PASSWORD must be set/ig
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
t.test('docker USER/PASS succeeds', async (tt) => {
|
|
60
|
+
const context = {
|
|
61
|
+
env: {
|
|
62
|
+
...process.env
|
|
63
|
+
, DOCKER_REGISTRY_USER: 'iamweasel'
|
|
64
|
+
, DOCKER_REGISTRY_PASSWORD: 'secretsquirrel'
|
|
65
|
+
}
|
|
66
|
+
, cwd: process.cwd()
|
|
67
|
+
, logger: {
|
|
68
|
+
success: sinon.stub()
|
|
69
|
+
, info: sinon.stub()
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const config = await buildConfig(build_id, {
|
|
73
|
+
dockerRegistry: DOCKER_REGISTRY_HOST
|
|
74
|
+
}, context)
|
|
75
|
+
tt.resolves(verify(config, context))
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
t.test('docker USER / GITHUB_TOKEN succeeds', async (tt) => {
|
|
79
|
+
const context = {
|
|
80
|
+
env: {
|
|
81
|
+
...process.env
|
|
82
|
+
, DOCKER_REGISTRY_USER: 'iamweasel'
|
|
83
|
+
, GITHUB_TOKEN: 'secretsquirrel'
|
|
84
|
+
}
|
|
85
|
+
, cwd: process.cwd()
|
|
86
|
+
, logger: {
|
|
87
|
+
success: sinon.stub()
|
|
88
|
+
, info: sinon.stub()
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const config = await buildConfig(build_id, {
|
|
92
|
+
dockerRegistry: DOCKER_REGISTRY_HOST
|
|
93
|
+
}, context)
|
|
94
|
+
tt.resolves(verify(config, context))
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
t.test('docker no login', async (tt) => {
|
|
98
|
+
const context = {
|
|
99
|
+
env: {
|
|
100
|
+
...process.env
|
|
101
|
+
, DOCKER_REGISTRY_USER: 'iamweasel'
|
|
102
|
+
}
|
|
103
|
+
, cwd: process.cwd()
|
|
104
|
+
, logger: {
|
|
105
|
+
success: sinon.stub()
|
|
106
|
+
, info: sinon.stub()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const config = await buildConfig(build_id, {
|
|
110
|
+
dockerRegistry: DOCKER_REGISTRY_HOST
|
|
111
|
+
, dockerLogin: false
|
|
112
|
+
}, context)
|
|
113
|
+
tt.resolves(verify(config, context))
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
t.test('docker password, no username', async (tt) => {
|
|
117
|
+
const context = {
|
|
118
|
+
env: {
|
|
119
|
+
...process.env
|
|
120
|
+
, DOCKER_REGISTRY_PASSWORD: 'abc123'
|
|
121
|
+
, DOCKER_REGISTRY_USER: 'abc123'
|
|
122
|
+
}
|
|
123
|
+
, cwd: process.cwd()
|
|
124
|
+
, logger: {
|
|
125
|
+
success: sinon.stub()
|
|
126
|
+
, info: sinon.stub()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const config = await buildConfig(build_id, {}, context)
|
|
130
|
+
tt.rejects(
|
|
131
|
+
verify(config, context)
|
|
132
|
+
, {
|
|
133
|
+
message: /docker authentication failed/i
|
|
134
|
+
, code: 'EAUTH'
|
|
135
|
+
, details: /authentication to dockerhub failed/ig
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
t.test('No auth provided succeed', async (tt) => {
|
|
141
|
+
const context = {
|
|
142
|
+
env: {
|
|
143
|
+
...process.env
|
|
144
|
+
}
|
|
145
|
+
, cwd: process.cwd()
|
|
146
|
+
, logger: {
|
|
147
|
+
success: sinon.stub()
|
|
148
|
+
, info: sinon.stub()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const config = await buildConfig(build_id, {}, context)
|
|
153
|
+
tt.strictEqual(await verify(config, context), false, 'auth step skipped')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
t.test('unable to collect image name', async (tt) => {
|
|
157
|
+
const context = {
|
|
158
|
+
env: {
|
|
159
|
+
...process.env
|
|
160
|
+
}
|
|
161
|
+
, cwd: __dirname
|
|
162
|
+
, logger: {
|
|
163
|
+
success: sinon.stub()
|
|
164
|
+
, info: sinon.stub()
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const config = await buildConfig(build_id, {
|
|
169
|
+
dockerRegistry: DOCKER_REGISTRY_HOST
|
|
170
|
+
}, context)
|
|
171
|
+
tt.rejects(verify(config, context), {
|
|
172
|
+
code: 'EINVAL'
|
|
173
|
+
, name: 'SemanticReleaseError'
|
|
174
|
+
, details: new RegExp(
|
|
175
|
+
'image name parsed from package.json name if possible. or via the "image" option'
|
|
176
|
+
, 'gi'
|
|
177
|
+
)
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
t.test('invalid docker file location', async (tt) => {
|
|
182
|
+
const context = {
|
|
183
|
+
env: {
|
|
184
|
+
...process.env
|
|
185
|
+
}
|
|
186
|
+
, cwd: process.cwd()
|
|
187
|
+
, logger: {
|
|
188
|
+
success: sinon.stub()
|
|
189
|
+
, info: sinon.stub()
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const config = await buildConfig(build_id, {
|
|
194
|
+
dockerRegistry: DOCKER_REGISTRY_HOST
|
|
195
|
+
, dockerFile: 'Notafile'
|
|
196
|
+
}, context)
|
|
197
|
+
|
|
198
|
+
await tt.rejects(verify(config, context), {
|
|
199
|
+
code: 'ENOENT'
|
|
200
|
+
, name: 'SemanticReleaseError'
|
|
201
|
+
, details: /relative to pwd/gi
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
})
|
|
205
|
+
}).catch(threw)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const {test, threw} = require('tap')
|
|
5
|
+
const buildConfig = require('../../lib/build-config.js')
|
|
6
|
+
|
|
7
|
+
test('build-config', async (t) => {
|
|
8
|
+
t.testdir({
|
|
9
|
+
standard: {
|
|
10
|
+
'package.json': JSON.stringify({name: 'this-is-not-scoped'})
|
|
11
|
+
}
|
|
12
|
+
, scoped: {
|
|
13
|
+
'package.json': JSON.stringify({name: '@scope/this-is-scoped'})
|
|
14
|
+
}
|
|
15
|
+
, workspace: {
|
|
16
|
+
one: {
|
|
17
|
+
'package.json': JSON.stringify({name: '@internal/package'})
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
t.test('standard package', async (tt) => {
|
|
23
|
+
const config = await buildConfig('id', {
|
|
24
|
+
}, {
|
|
25
|
+
cwd: path.join(t.testdirName, 'standard')
|
|
26
|
+
})
|
|
27
|
+
tt.match(config, {
|
|
28
|
+
dockerfile: 'Dockerfile'
|
|
29
|
+
, publish: true
|
|
30
|
+
, nocache: false
|
|
31
|
+
, tags: ['latest', '{major}-latest', '{version}']
|
|
32
|
+
, args: {
|
|
33
|
+
SRC_DIRECTORY: 'standard'
|
|
34
|
+
, TARGET_PATH: '.'
|
|
35
|
+
, NPM_PACKAGE_NAME: 'this-is-not-scoped'
|
|
36
|
+
, NPM_PACKAGE_SCOPE: null
|
|
37
|
+
, CONFIG_NAME: 'this-is-not-scoped'
|
|
38
|
+
, CONFIG_PROJECT: null
|
|
39
|
+
}
|
|
40
|
+
, pkg: Object
|
|
41
|
+
, registry: null
|
|
42
|
+
, name: 'this-is-not-scoped'
|
|
43
|
+
, project: null
|
|
44
|
+
, build: 'id'
|
|
45
|
+
, context: '.'
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
t.test('nested workspace: target resolution', async (tt) => {
|
|
50
|
+
const config = await buildConfig('id', {
|
|
51
|
+
}, {
|
|
52
|
+
options: {
|
|
53
|
+
root: t.testdirName
|
|
54
|
+
}
|
|
55
|
+
, cwd: path.join(t.testdirName, 'workspace', 'one')
|
|
56
|
+
})
|
|
57
|
+
tt.match(config, {
|
|
58
|
+
dockerfile: 'Dockerfile'
|
|
59
|
+
, nocache: false
|
|
60
|
+
, publish: true
|
|
61
|
+
, tags: ['latest', '{major}-latest', '{version}']
|
|
62
|
+
, args: {
|
|
63
|
+
SRC_DIRECTORY: 'one'
|
|
64
|
+
, TARGET_PATH: 'workspace/one'
|
|
65
|
+
, NPM_PACKAGE_NAME: 'package'
|
|
66
|
+
, NPM_PACKAGE_SCOPE: 'internal'
|
|
67
|
+
, CONFIG_NAME: 'package'
|
|
68
|
+
, CONFIG_PROJECT: 'internal'
|
|
69
|
+
}
|
|
70
|
+
, pkg: Object
|
|
71
|
+
, registry: null
|
|
72
|
+
, name: 'package'
|
|
73
|
+
, project: 'internal'
|
|
74
|
+
, build: 'id'
|
|
75
|
+
, context: '.'
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
t.test('scoped package', async (tt) => {
|
|
80
|
+
{
|
|
81
|
+
const config = await buildConfig('id', {
|
|
82
|
+
}, {
|
|
83
|
+
cwd: path.join(t.testdirName, 'scoped')
|
|
84
|
+
})
|
|
85
|
+
tt.match(config, {
|
|
86
|
+
dockerfile: 'Dockerfile'
|
|
87
|
+
, nocache: false
|
|
88
|
+
, tags: ['latest', '{major}-latest', '{version}']
|
|
89
|
+
, args: {
|
|
90
|
+
SRC_DIRECTORY: 'scoped'
|
|
91
|
+
, TARGET_PATH: '.'
|
|
92
|
+
, NPM_PACKAGE_NAME: '@scope/this-is-scoped'
|
|
93
|
+
, NPM_PACKAGE_SCOPE: 'scope'
|
|
94
|
+
, CONFIG_NAME: 'this-is-scoped'
|
|
95
|
+
, CONFIG_PROJECT: 'scope'
|
|
96
|
+
}
|
|
97
|
+
, pkg: Object
|
|
98
|
+
, registry: null
|
|
99
|
+
, name: 'this-is-scoped'
|
|
100
|
+
, project: 'scope'
|
|
101
|
+
, build: 'id'
|
|
102
|
+
, context: '.'
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
const config = await buildConfig('id', {
|
|
108
|
+
dockerProject: 'kittens'
|
|
109
|
+
, dockerImage: 'override'
|
|
110
|
+
, dockerFile: 'Dockerfile.test'
|
|
111
|
+
, dockerPublish: false
|
|
112
|
+
}, {
|
|
113
|
+
cwd: path.join(t.testdirName, 'scoped')
|
|
114
|
+
})
|
|
115
|
+
tt.match(config, {
|
|
116
|
+
dockerfile: 'Dockerfile.test'
|
|
117
|
+
, publish: false
|
|
118
|
+
, nocache: false
|
|
119
|
+
, tags: ['latest', '{major}-latest', '{version}']
|
|
120
|
+
, args: {
|
|
121
|
+
SRC_DIRECTORY: 'scoped'
|
|
122
|
+
, TARGET_PATH: '.'
|
|
123
|
+
, NPM_PACKAGE_NAME: '@scope/this-is-scoped'
|
|
124
|
+
, NPM_PACKAGE_SCOPE: 'scope'
|
|
125
|
+
, CONFIG_NAME: 'override'
|
|
126
|
+
, CONFIG_PROJECT: 'kittens'
|
|
127
|
+
}
|
|
128
|
+
, pkg: Object
|
|
129
|
+
, registry: null
|
|
130
|
+
, name: 'override'
|
|
131
|
+
, project: 'kittens'
|
|
132
|
+
, build: 'id'
|
|
133
|
+
, context: '.'
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
{
|
|
138
|
+
const config = await buildConfig('id', {
|
|
139
|
+
dockerProject: null
|
|
140
|
+
, dockerImage: 'override'
|
|
141
|
+
, dockerFile: 'Dockerfile.test'
|
|
142
|
+
, dockerTags: 'latest,{major}-latest , fake, {version}'
|
|
143
|
+
}, {
|
|
144
|
+
cwd: path.join(t.testdirName, 'scoped')
|
|
145
|
+
})
|
|
146
|
+
tt.match(config, {
|
|
147
|
+
dockerfile: 'Dockerfile.test'
|
|
148
|
+
, nocache: false
|
|
149
|
+
, tags: ['latest', '{major}-latest', 'fake', '{version}']
|
|
150
|
+
, args: {
|
|
151
|
+
SRC_DIRECTORY: 'scoped'
|
|
152
|
+
, TARGET_PATH: '.'
|
|
153
|
+
, NPM_PACKAGE_NAME: '@scope/this-is-scoped'
|
|
154
|
+
, NPM_PACKAGE_SCOPE: 'scope'
|
|
155
|
+
, CONFIG_NAME: 'override'
|
|
156
|
+
, CONFIG_PROJECT: null
|
|
157
|
+
}
|
|
158
|
+
, pkg: Object
|
|
159
|
+
, registry: null
|
|
160
|
+
, name: 'override'
|
|
161
|
+
, project: null
|
|
162
|
+
, build: 'id'
|
|
163
|
+
, context: '.'
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}).catch(threw)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {test, threw} = require('tap')
|
|
4
|
+
const buildConfig = require('../../lib/build-config.js')
|
|
5
|
+
const buildTemplateVars = require('../../lib/build-template-vars.js')
|
|
6
|
+
|
|
7
|
+
test('buildTemplateVars', async (t) => {
|
|
8
|
+
const cwd = t.testdir({
|
|
9
|
+
'package.json': JSON.stringify({
|
|
10
|
+
name: 'template-vars'
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
const context = {
|
|
14
|
+
cwd
|
|
15
|
+
, nextRelease: {
|
|
16
|
+
version: '1.0.0'
|
|
17
|
+
, gitTag: 'v1.0.0'
|
|
18
|
+
, gitHead: 'abcdefgh'
|
|
19
|
+
, type: 'major'
|
|
20
|
+
, notes: 'test it'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const opts = await buildConfig('abacadaba', {
|
|
24
|
+
dockerArgs: {
|
|
25
|
+
TEMPLATE_VALUE: '{type}.{version}'
|
|
26
|
+
, BOOLEAN_VALUE: true
|
|
27
|
+
, NULL_VALUE: null
|
|
28
|
+
}
|
|
29
|
+
}, context)
|
|
30
|
+
|
|
31
|
+
const vars = buildTemplateVars(opts, context)
|
|
32
|
+
t.match(vars, {
|
|
33
|
+
release_type: 'major'
|
|
34
|
+
, release_notes: 'test it'
|
|
35
|
+
, version: '1.0.0'
|
|
36
|
+
, git_sha: 'abcdefgh'
|
|
37
|
+
, git_tag: 'v1.0.0'
|
|
38
|
+
, pkg: {name: 'template-vars'}
|
|
39
|
+
, major: 1
|
|
40
|
+
, minor: 0
|
|
41
|
+
, patch: 0
|
|
42
|
+
, version: '1.0.0'
|
|
43
|
+
, next: {
|
|
44
|
+
major: 1
|
|
45
|
+
, minor: 0
|
|
46
|
+
, patch: 0
|
|
47
|
+
, version: '1.0.0'
|
|
48
|
+
}
|
|
49
|
+
, args: {
|
|
50
|
+
SRC_DIRECTORY: String
|
|
51
|
+
, TARGET_PATH: String
|
|
52
|
+
, NPM_PACKAGE_NAME: 'template-vars'
|
|
53
|
+
, NPM_PACKAGE_SCOPE: null
|
|
54
|
+
, CONFIG_NAME: String
|
|
55
|
+
, CONFIG_PROJECT: null
|
|
56
|
+
, GIT_SHA: 'abcdefgh'
|
|
57
|
+
, GIT_TAG: 'v1.0.0'
|
|
58
|
+
, TEMPLATE_VALUE: '{type}.{version}'
|
|
59
|
+
, BOOLEAN_VALUE: true
|
|
60
|
+
, NULL_VALUE: null
|
|
61
|
+
}
|
|
62
|
+
}, 'expected template values')
|
|
63
|
+
}).catch(threw)
|