Skip to content

Commit

Permalink
feat: buildkite plugin renovation (#1874)
Browse files Browse the repository at this point in the history
This PR adds initial support for buildkite plugin renovation.

It supports `plugin-name` or `my/plugin-name` plugins, and fully specified semver versions only (e.g. `v1.3.2`). Currently it will always propose an upgrade to the latest version available, e.g. if current version is v1.3.1 and both v1.3.2 and v2.0.0 exist then v2.0.0 will be proposed. Looks for any yml file in the `.buildkite/` directory.

Closes #1869
  • Loading branch information
rarkins authored Apr 27, 2018
1 parent 4bd721b commit 4349a21
Show file tree
Hide file tree
Showing 17 changed files with 483 additions and 0 deletions.
14 changes: 14 additions & 0 deletions lib/config/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,20 @@ const options = [
default: {},
mergeable: true,
},
{
name: 'buildkite',
description: 'Configuration object for buildkite pipeline renovation',
stage: 'repository',
type: 'json',
default: {
enabled: false,
commitMessageTopic: 'buildkite plugin {{depName}}',
commitMessageExtra: 'to {{newVersion}}',
managerBranchPrefix: 'buildkite-',
prBody: template('prBody', 'buildkite'),
},
mergeable: true,
},
{
name: 'supportPolicy',
description:
Expand Down
72 changes: 72 additions & 0 deletions lib/config/templates/buildkite/pr-body.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
This Pull Request updates buildkite plugin {{#if repositoryUrl}}[{{{depName}}}]({{{repositoryUrl}}}){{else}}`{{{depName}}}`{{/if}} from `{{{currentVersion}}}` to `{{{newVersion}}}`.

{{#if releases.length}}

{{#if schedule}}
**Note**: This PR was created on a configured schedule ("{{{schedule}}}"{{#if timezone}} in timezone `{{{timezone}}}`{{/if}}) and will not receive updates outside those times.
{{/if}}

{{#if isPin}}
**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.
{{/if}}
{{#if hasReleaseNotes}}

<details>
<summary>Release Notes</summary>

{{#each releases as |release|}}
{{#if release.releaseNotes}}
### [`v{{{release.version}}}`]({{{release.releaseNotes.url}}})

{{{release.releaseNotes.body}}}

---
{{/if}}
{{/each}}
</details>
{{/if}}
{{#if hasCommits}}
<details>
<summary>Commits</summary>
{{#each releases as |release|}}
{{#if release.hasCommits}}
#### v{{{release.version}}}
{{#each release.commits as |commit|}}
- [`{{commit.shortSha}}`]({{commit.url}}) {{commit.message}}
{{/each}}
{{/if}}
{{/each}}
</details>
{{/if}}
{{/if}}
{{#if hasErrors}}
---

# Errors

Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.

{{#each errors as |error|}}
- `{{error.depName}}`: {{error.message}}
{{/each}}
{{/if}}

{{#if hasWarnings}}

---
# Warnings
Please make sure the following warnings are safe to ignore:
{{#each warnings as |warning|}}
- `{{warning.depName}}`: {{warning.message}}
{{/each}}
{{/if}}
39 changes: 39 additions & 0 deletions lib/manager/buildkite/extract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = {
extractDependencies,
};

function extractDependencies(content) {
logger.debug('buildkite.extractDependencies()');
logger.trace({ content });
const deps = [];
try {
const lines = content.split('\n');
for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
const line = lines[lineNumber];
const plugins = line.match(/^\s*-?\s*plugins:\s*$/);
if (plugins) {
logger.trace(`Matched plugins on line ${lineNumber}`);
const depLine = lines[lineNumber + 1];
logger.debug(`serviceImageLine: "${depLine}"`);
const depLineMatch = depLine.match(/^\s+([^#]+)#([^:]+):/);
if (depLineMatch) {
logger.trace('depLineMatch');
lineNumber += 1;
const [, depName, currentVersion] = depLineMatch;
deps.push({
depType: 'plugins',
lineNumber,
depName,
currentVersion,
});
}
}
}
} catch (err) /* istanbul ignore next */ {
logger.error(
{ err, message: err.message },
'Error extracting buildkite plugins'
);
}
return deps;
}
12 changes: 12 additions & 0 deletions lib/manager/buildkite/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { extractDependencies } = require('./extract');
const { getPackageUpdates } = require('./package');
const { updateDependency } = require('./update');

const filePattern = new RegExp('\\.buildkite/.+\\.yml$');

module.exports = {
extractDependencies,
filePattern,
getPackageUpdates,
updateDependency,
};
56 changes: 56 additions & 0 deletions lib/manager/buildkite/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const {
isGreaterThan,
isPinnedVersion,
semverSort,
getMajor,
getMinor,
} = require('../../util/semver');
const { getRepoTags } = require('../../datasource/github');

module.exports = {
getPackageUpdates,
};

async function getPackageUpdates(config) {
const { depName, currentVersion } = config;
logger.debug({ depName }, 'buildkite.getPackageUpdates()');
if (depName.startsWith('https://') || depName.startsWith('git@')) {
logger.debug({ depName }, 'Skipping git plugin');
return [];
}
if (!isPinnedVersion(currentVersion)) {
logger.debug({ currentVersion }, 'Skipping non-pinned current version');
return [];
}
let sourceRepo = '';
const splitName = depName.split('/');
if (splitName.length === 1) {
sourceRepo = `buildkite-plugins/${depName}-buildkite-plugin`;
} else if (splitName.length === 2) {
sourceRepo = `${depName}-buildkite-plugin`;
} else {
logger.warn({ depName }, 'Something is wrong with buildkite plugin name');
return [];
}
const repoTags = await getRepoTags(sourceRepo);
const newerVersions = repoTags
.filter(tag => isGreaterThan(tag, currentVersion))
.sort(semverSort);
if (newerVersions.length) {
logger.debug({ newerVersions }, 'Found newer versions');
} else {
return [];
}
const newVersion = newerVersions.pop();
return [
{
type: getMajor(newVersion) > getMajor(currentVersion) ? 'major' : 'minor',
newVersion,
newVersionMajor: getMajor(newVersion),
newVersionMinor: getMinor(newVersion),
changeLogFromVersion: currentVersion,
changeLogToVersion: newVersion,
repositoryUrl: `https://github.com/${sourceRepo}`,
},
];
}
26 changes: 26 additions & 0 deletions lib/manager/buildkite/update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module.exports = {
updateDependency,
};

function updateDependency(currentFileContent, upgrade) {
try {
logger.debug(`buildkite.updateDependency: ${upgrade.newVersion}`);
const lines = currentFileContent.split('\n');
const lineToChange = lines[upgrade.lineNumber];
const depLine = new RegExp(/^(\s+[^#]+#)[^:]+(:.*)$/);
if (!lineToChange.match(depLine)) {
logger.debug('No image line found');
return null;
}
const newLine = lineToChange.replace(depLine, `$1${upgrade.newVersion}$2`);
if (newLine === lineToChange) {
logger.debug('No changes necessary');
return currentFileContent;
}
lines[upgrade.lineNumber] = newLine;
return lines.join('\n');
} catch (err) {
logger.info({ err }, 'Error setting new buildkite version');
return null;
}
}
1 change: 1 addition & 0 deletions lib/manager/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { checkMonorepos } = require('../manager/npm/monorepos');
const managers = {};
const managerList = [
'bazel',
'buildkite',
'circleci',
'docker',
'docker-compose',
Expand Down
3 changes: 3 additions & 0 deletions test/_fixtures/buildkite/pipeline1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
steps:
- plugins:
detect-clowns#v2.0.0: ~
17 changes: 17 additions & 0 deletions test/_fixtures/buildkite/pipeline2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
steps:
# Prebuild the app image, upload it to a registry for later steps
- name: "Docker Build"
plugins:
docker-compose#v1.3.2:
build: app
image-repository: index.docker.io/org/repo

- wait

# Use the app image built above to run concurrent tests
- name: "Docker Test %n"
command: test.sh
parallelism: 25
plugins:
docker-compose#v1.3.2:
run: app
7 changes: 7 additions & 0 deletions test/config/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ Object {
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
"branchPrefix": "renovate/",
"branchTopic": "{{{depNameSanitized}}}-{{{newVersionMajor}}}.x",
"buildkite": Object {
"commitMessageExtra": "to {{newVersion}}",
"commitMessageTopic": "buildkite plugin {{depName}}",
"enabled": false,
"managerBranchPrefix": "buildkite-",
"prBody": "This Pull Request updates buildkite plugin {{#if repositoryUrl}}[{{{depName}}}]({{{repositoryUrl}}}){{else}}\`{{{depName}}}\`{{/if}} from \`{{{currentVersion}}}\` to \`{{{newVersion}}}\`.\\n\\n{{#if releases.length}}\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if isPin}}\\n**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.\\n{{/if}}\\n{{#if hasReleaseNotes}}\\n\\n<details>\\n<summary>Release Notes</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.releaseNotes}}\\n### [\`v{{{release.version}}}\`]({{{release.releaseNotes.url}}})\\n\\n{{{release.releaseNotes.body}}}\\n\\n---\\n\\n{{/if}}\\n{{/each}}\\n</details>\\n{{/if}}\\n\\n{{#if hasCommits}}\\n\\n<details>\\n<summary>Commits</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.hasCommits}}\\n#### v{{{release.version}}}\\n{{#each release.commits as |commit|}}\\n- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}}\\n{{/each}}\\n{{/if}}\\n{{/each}}\\n\\n</details>\\n{{/if}}\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}",
},
"bumpVersion": null,
"circleci": Object {},
"commitBody": null,
Expand Down
29 changes: 29 additions & 0 deletions test/manager/buildkite/__snapshots__/extract.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`lib/manager/buildkite/extract extractDependencies() extracts multiple plugins in same file 1`] = `
Array [
Object {
"currentVersion": "v1.3.2",
"depName": "docker-compose",
"depType": "plugins",
"lineNumber": 4,
},
Object {
"currentVersion": "v1.3.2",
"depName": "docker-compose",
"depType": "plugins",
"lineNumber": 15,
},
]
`;

exports[`lib/manager/buildkite/extract extractDependencies() extracts simple single plugin 1`] = `
Array [
Object {
"currentVersion": "v2.0.0",
"depName": "detect-clowns",
"depType": "plugins",
"lineNumber": 2,
},
]
`;
15 changes: 15 additions & 0 deletions test/manager/buildkite/__snapshots__/package.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`lib/manager/buildkite/package getPackageUpdates() returns one upgrade 1`] = `
Array [
Object {
"changeLogFromVersion": "v1.0.0",
"changeLogToVersion": "v1.2.0",
"newVersion": "v1.2.0",
"newVersionMajor": 1,
"newVersionMinor": 2,
"repositoryUrl": "https://github.com/some/plugin-buildkite-plugin",
"type": "minor",
},
]
`;
22 changes: 22 additions & 0 deletions test/manager/buildkite/__snapshots__/update.spec.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`manager/buildkite/update updateDependency replaces two values in one file 1`] = `
"steps:
# Prebuild the app image, upload it to a registry for later steps
- name: \\"Docker Build\\"
plugins:
docker-compose#v1.5.0:
build: app
image-repository: index.docker.io/org/repo
- wait
# Use the app image built above to run concurrent tests
- name: \\"Docker Test %n\\"
command: test.sh
parallelism: 25
plugins:
docker-compose#v1.5.0:
run: app
"
`;
32 changes: 32 additions & 0 deletions test/manager/buildkite/extract.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const fs = require('fs');
const {
extractDependencies,
} = require('../../../lib/manager/buildkite/extract');

const pipeline1 = fs.readFileSync(
'test/_fixtures/buildkite/pipeline1.yml',
'utf8'
);
const pipeline2 = fs.readFileSync(
'test/_fixtures/buildkite/pipeline2.yml',
'utf8'
);

describe('lib/manager/buildkite/extract', () => {
describe('extractDependencies()', () => {
let config;
beforeEach(() => {
config = {};
});
it('extracts simple single plugin', () => {
const res = extractDependencies(pipeline1, config);
expect(res).toMatchSnapshot();
expect(res).toHaveLength(1);
});
it('extracts multiple plugins in same file', () => {
const res = extractDependencies(pipeline2, config);
expect(res).toMatchSnapshot();
expect(res).toHaveLength(2);
});
});
});
Loading

0 comments on commit 4349a21

Please sign in to comment.