Skip to content

Commit 054a534

Browse files
authored
Merge pull request #4 from levibostian/beta
2 parents 6d2e8ab + 4bd4854 commit 054a534

17 files changed

+477
-2
lines changed

.npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

.travis.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: ~> 1.0
2+
3+
services:
4+
- docker
5+
6+
import:
7+
- semantic-release/semantic-release:.travis/node.yml
8+
- semantic-release/semantic-release:.travis/node-versions.yml
9+
- semantic-release/semantic-release:.travis/semantic-release.yml
10+
- semantic-release/semantic-release:.travis/greenkeeper.yml
11+
- semantic-release/semantic-release:.travis/codecov.yml

.yarnrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--install.no-lockfile true

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
[![Travis](https://img.shields.io/travis/levibostian/semantic-release-cocoapods.svg)](https://travis-ci.org/levibostian/semantic-release-cocoapods)
2-
[![npm latest version](https://img.shields.io/npm/v/levibostian/semantic-release-cocoapods/latest.svg)](https://www.npmjs.com/package/levibostian/semantic-release-cocoapods)
1+
[![Travis](https://travis-ci.com/levibostian/semantic-release-cocoapods.svg?branch=master)](https://travis-ci.org/levibostian/semantic-release-cocoapods)
2+
[![npm latest version](https://img.shields.io/npm/v/semantic-release-cocoapods/latest.svg)](https://www.npmjs.com/package/semantic-release-cocoapods)
33

44
# semantic-release-cocoapods
55

index.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const {defaultTo} = require('lodash');
2+
const AggregateError = require('aggregate-error');
3+
const verifyPluginConfig = require('./lib/verify-config');
4+
const verifyPodAuth = require('./lib/verify-auth');
5+
const verifyCliInstalled = require('./lib/verify-cli-installed');
6+
const verifyPodLint = require('./lib/verify-pod-lint');
7+
const preparePod = require('./lib/prepare');
8+
const publishPod = require('./lib/publish');
9+
10+
// Let verified;
11+
let prepared;
12+
13+
async function verifyConditions(pluginConfig, context) {
14+
// Set default values for config
15+
pluginConfig.podLint = defaultTo(pluginConfig.podLint, true);
16+
pluginConfig.podLintArgs = defaultTo(pluginConfig.podLintArgs, '');
17+
pluginConfig.podPushArgs = defaultTo(pluginConfig.podPushArgs, '');
18+
19+
const errors = verifyPluginConfig(pluginConfig);
20+
21+
try {
22+
// 1. Verify `pod` command exists
23+
await verifyCliInstalled(pluginConfig, context);
24+
25+
// 2. Verify `COCOAPODS_TRUNK_TOKEN` environment variable exists
26+
// 3. Verify `pod trunk me` is successful.
27+
await verifyPodAuth(pluginConfig, context);
28+
29+
// 4. Verify `pod lib lint` is successful
30+
await verifyPodLint(pluginConfig, context);
31+
} catch (error) {
32+
errors.push(...error);
33+
}
34+
35+
if (errors.length > 0) {
36+
throw new AggregateError(errors);
37+
}
38+
39+
// Verified = true;
40+
}
41+
42+
async function prepare(pluginConfig, context) {
43+
await preparePod(pluginConfig, context);
44+
prepared = true;
45+
}
46+
47+
async function publish(pluginConfig, context) {
48+
if (!prepared) {
49+
await preparePod(pluginConfig, context);
50+
}
51+
52+
return publishPod(pluginConfig, context);
53+
}
54+
55+
module.exports = {verifyConditions, prepare, publish};

lib/definitions/errors.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module.exports = {
2+
EINVALIDPODLINT: ({podLint}) => ({
3+
message: 'Invalid `podLint` option.',
4+
details: `The podLint option, if defined, must be a \`Boolean\`.
5+
6+
Your configuration for the \`podLint\` option is \`${podLint}\`.`,
7+
}),
8+
EINVALIDPODLINTARGS: ({podLintArgs}) => ({
9+
message: 'Invalid `podLintArgs` option.',
10+
details: `The podLintArgs option, if defined, must be a \`String\`.
11+
12+
Your configuration for the \`podLintArgs\` option is \`${podLintArgs}\`.`,
13+
}),
14+
EINVALIDPODPUSHARGS: ({podPushArgs}) => ({
15+
message: 'Invalid `podPushArgs` option.',
16+
details: `The podPushArgs option, if defined, must be a \`String\`.
17+
18+
Your configuration for the \`podPushArgs\` option is \`${podPushArgs}\`.`,
19+
}),
20+
ECLINOTINSTALLED: () => ({
21+
message: "You do not have 'pod' installed on your machine.",
22+
details: `You must have 'pod' installed to work with cocoapods. [Install the 'pod' CLI](https://cocoapods.org/) then try again.`,
23+
}),
24+
ENOPODTOKEN: () => ({
25+
message: 'No cocoapods trunk token specified.',
26+
details: `An cocoapods token must be created and set in the \`COCOAPODS_TRUNK_TOKEN\` environment variable on your CI environment for the cocoapods account you want to push the pod update for.`,
27+
}),
28+
EINVALIDPODTOKEN: () => ({
29+
message: 'Invalid cocoapods trunk token.',
30+
details: `The cocoapods token configured in the \`COCOAPODS_TRUNK_TOKEN\` environment variable must be a valid. This token is not associated with a valid user and/or session.`,
31+
}),
32+
};

lib/get-error.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const SemanticReleaseError = require('@semantic-release/error');
2+
const ERROR_DEFINITIONS = require('./definitions/errors');
3+
4+
module.exports = (code, ctx = {}) => {
5+
const {message, details} = ERROR_DEFINITIONS[code](ctx);
6+
return new SemanticReleaseError(message, code, details);
7+
};

lib/prepare.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const replaceInFile = require('replace-in-file');
2+
3+
module.exports = async (pluginConfig, context) => {
4+
const {
5+
cwd,
6+
nextRelease: {version},
7+
logger,
8+
} = context;
9+
10+
logger.log(`Write version ${version} to ${cwd}/*.podspec`);
11+
12+
// https://regexr.com/56ik3
13+
const replaceInFileOptions = {
14+
files: `${cwd}/*.podspec`,
15+
from: /\.version\s*=.*/g,
16+
to: (match) => {
17+
// We want to preserve whitespace. So, we are only going to replace the `= 'X.X.X'` part of the string.
18+
// regexr.com/56oig
19+
return match.replace(/=.*/g, `= '${version}'`);
20+
},
21+
};
22+
23+
await replaceInFile(replaceInFileOptions);
24+
};

lib/publish.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const execa = require('execa');
2+
3+
module.exports = async (pluginConfig, context) => {
4+
const {
5+
cwd,
6+
env,
7+
stdout,
8+
stderr,
9+
nextRelease: {version},
10+
logger,
11+
} = context;
12+
13+
logger.log(`Publishing version ${version} to cocoapods`);
14+
15+
const result = execa('pod', ['trunk', 'push', pluginConfig.podPushArgs], {cwd, env});
16+
result.stdout.pipe(stdout, {end: false});
17+
result.stderr.pipe(stderr, {end: false});
18+
await result;
19+
20+
logger.log(`Published ${version} to cocoapods!`);
21+
22+
return {version};
23+
};

lib/verify-auth.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const execa = require('execa');
2+
const AggregateError = require('aggregate-error');
3+
const getError = require('./get-error');
4+
5+
module.exports = async (pluginConfig, context) => {
6+
const {cwd, env, stdout, stderr, logger} = context;
7+
8+
logger.log(`Checking if token environment variable set`);
9+
if (!env.COCOAPODS_TRUNK_TOKEN) {
10+
throw new AggregateError([getError('ENOPODTOKEN', {})]);
11+
}
12+
13+
try {
14+
logger.log(`Checking if authenticated with cocoapods with valid account and session.`);
15+
16+
const result = execa('pod', ['trunk', 'me', '--silent'], {cwd, env});
17+
result.stdout.pipe(stdout, {end: false});
18+
result.stderr.pipe(stderr, {end: false});
19+
await result;
20+
} catch (_) {
21+
throw new AggregateError([getError('EINVALIDPODTOKEN', {})]);
22+
}
23+
};

lib/verify-cli-installed.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const execa = require('execa');
2+
const AggregateError = require('aggregate-error');
3+
const getError = require('./get-error');
4+
5+
module.exports = async (pluginConfig, context) => {
6+
const {cwd, env, stdout, stderr, logger} = context;
7+
try {
8+
logger.log(`Verifying 'pod' installed on machine`);
9+
const result = execa('command', ['-v', 'pod'], {cwd, env});
10+
result.stdout.pipe(stdout, {end: false});
11+
result.stderr.pipe(stderr, {end: false});
12+
await result;
13+
} catch (_) {
14+
throw new AggregateError([getError('ECLINOTINSTALLED', {})]);
15+
}
16+
};

lib/verify-config.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const {isString, isNil, isBoolean} = require('lodash');
2+
const getError = require('./get-error');
3+
4+
const VALIDATORS = {
5+
podLint: isBoolean,
6+
podLintArgs: isString,
7+
podPushArgs: isString,
8+
};
9+
10+
module.exports = ({podLint, podLintArgs, podPushArgs}) => {
11+
const errors = Object.entries({podLint, podLintArgs, podPushArgs}).reduce(
12+
(errors, [option, value]) =>
13+
!isNil(value) && !VALIDATORS[option](value)
14+
? [...errors, getError(`EINVALID${option.toUpperCase()}`, {[option]: value})]
15+
: errors,
16+
[]
17+
);
18+
19+
return errors;
20+
};

lib/verify-pod-lint.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const execa = require('execa');
2+
const AggregateError = require('aggregate-error');
3+
const getError = require('./get-error');
4+
5+
module.exports = async (pluginConfig, context) => {
6+
const {cwd, env, stdout, stderr, logger} = context;
7+
8+
if (!pluginConfig.podLint) {
9+
logger.log(`pod lib lint being skipped. Disabled through plugin configuration`);
10+
return;
11+
}
12+
13+
try {
14+
logger.log(`Running 'pod lib lint' to verify lib ready for publishing.`);
15+
16+
const result = execa('pod', ['lib', 'lint', pluginConfig.podLintArgs], {cwd, env});
17+
result.stdout.pipe(stdout, {end: false});
18+
result.stderr.pipe(stderr, {end: false});
19+
await result;
20+
} catch (_) {
21+
throw new AggregateError([getError('ECLINOTINSTALLED', {})]);
22+
}
23+
};

package.json

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"name": "semantic-release-cocoapods",
3+
"description": "Cocoapods publishing plugin for semantic-release ",
4+
"version": "0.0.0-development",
5+
"author": "Levi Bostian (https://github.com/levibostian/)",
6+
"ava": {
7+
"files": [
8+
"test/**/*.test.js"
9+
],
10+
"timeout": "2m"
11+
},
12+
"bugs": {
13+
"url": "https://github.com/levibostian/semantic-release-cocoapods/issues"
14+
},
15+
"dependencies": {
16+
"@semantic-release/error": "^2.2.0",
17+
"aggregate-error": "^3.0.0",
18+
"execa": "^4.0.0",
19+
"lodash": "^4.17.15",
20+
"replace-in-file": "^6.1.0"
21+
},
22+
"devDependencies": {
23+
"ava": "^3.1.0",
24+
"codecov": "^3.0.0",
25+
"dockerode": "^3.0.0",
26+
"nyc": "^15.0.0",
27+
"semantic-release": "^17.0.0",
28+
"sinon": "^9.0.0",
29+
"stream-buffers": "^3.0.2",
30+
"xo": "^0.29.0"
31+
},
32+
"files": [
33+
"lib",
34+
"index.js"
35+
],
36+
"homepage": "https://github.com/levibostian/semantic-release-cocoapods#readme",
37+
"keywords": [
38+
"cocoapods",
39+
"publish",
40+
"registry",
41+
"semantic-release",
42+
"version"
43+
],
44+
"license": "MIT",
45+
"main": "index.js",
46+
"nyc": {
47+
"include": [
48+
"lib/**/*.js",
49+
"index.js"
50+
],
51+
"reporter": [
52+
"json",
53+
"text",
54+
"html"
55+
],
56+
"all": true
57+
},
58+
"peerDependencies": {
59+
"semantic-release": ">=16.0.0 <18.0.0"
60+
},
61+
"prettier": {
62+
"printWidth": 120,
63+
"trailingComma": "es5"
64+
},
65+
"publishConfig": {
66+
"access": "public"
67+
},
68+
"repository": {
69+
"type": "git",
70+
"url": "https://github.com/levibostian/semantic-release-cocoapods.git"
71+
},
72+
"scripts": {
73+
"codecov": "codecov -f coverage/coverage-final.json",
74+
"lint": "xo",
75+
"pretest": "npm run lint",
76+
"semantic-release": "semantic-release",
77+
"test": "nyc ava -v"
78+
},
79+
"xo": {
80+
"prettier": true,
81+
"space": true,
82+
"rules": {
83+
"unicorn/string-content": "off"
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)