Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tekton): support pipelinesascode annotation #26033

Merged
26 changes: 26 additions & 0 deletions lib/modules/manager/tekton/__fixtures__/multi-doc-annotations.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
kind: PipelineRun
metadata:
annotations:
pipelinesascode.tekton.dev/on-event: "[pull_request]"
pipelinesascode.tekton.dev/task: "[git-clone,https://github.com/foo/bar/releases/download/v0.0.4/stakater-create-git-tag.yaml]"
---
kind: PipelineRun
metadata:
annotations:
pipelinesascode.tekton.dev/task: "[git-clone,
https://raw.githubusercontent.com/foo/bar/v0.0.6/tasks/create-git-tag/create-git-tag.yaml]"
---
kind: PipelineRun
metadata:
annotations:
pipelinesascode.tekton.dev/task: "git-clone"
pipelinesascode.tekton.dev/task-1: "https://github.com/foo/bar/raw/v0.0.8/tasks/create-git-tag/create-git-tag.yaml"
---
kind: PipelineRun
metadata:
annotations:
pipelinesascode.tekton.dev/task: "[git-clone,
https://github.com/foo/bar/releases/download/v0.0.9/stakater-create-git-tag.yaml,
https://github.com/foo/bar/raw/v0.0.7/tasks/create-git-tag/create-git-tag.yaml,
https://raw.githubusercontent.com/foo/bar/v0.0.5/tasks/create-git-tag/create-git-tag.yaml]"
54 changes: 54 additions & 0 deletions lib/modules/manager/tekton/extract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,60 @@ describe('modules/manager/tekton/extract', () => {
expect(result?.deps).toHaveLength(39);
});

it('extracts deps from a file in annotations', () => {
const result = extractPackageFile(
Fixtures.get('multi-doc-annotations.yaml'),
'test-file.yaml',
);
expect(result).toEqual({
deps: [
{
currentValue: 'v0.0.4',
datasource: 'github-releases',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'foo/bar',
},
{
currentValue: 'v0.0.6',
datasource: 'git-tags',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'https://github.com/foo/bar',
},
{
currentValue: 'v0.0.8',
datasource: 'git-tags',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'https://github.com/foo/bar',
},
{
currentValue: 'v0.0.9',
datasource: 'github-releases',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'foo/bar',
},
{
currentValue: 'v0.0.7',
datasource: 'git-tags',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'https://github.com/foo/bar',
},
{
currentValue: 'v0.0.5',
datasource: 'git-tags',
depName: 'github.com/foo/bar',
depType: 'tekton-annotation',
packageName: 'https://github.com/foo/bar',
},
],
});
expect(result?.deps).toHaveLength(6);
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
});

it('ignores file without any deps', () => {
expect(extractPackageFile('foo: bar', 'test-file.yaml')).toBeNull();
});
Expand Down
73 changes: 73 additions & 0 deletions lib/modules/manager/tekton/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import type {
TektonResource,
TektonResourceSpec,
} from './types';
import { regEx } from '../../../util/regex';
import { GithubReleasesDatasource } from '../../datasource/github-releases';
import { GitTagsDatasource } from '../../datasource/git-tags';

export function extractPackageFile(
content: string,
Expand Down Expand Up @@ -52,6 +55,8 @@ function getDeps(doc: TektonResource): PackageDependency[] {
// Handle PipelineRun resource
addDep(doc.spec?.pipelineRef, deps);

addPipelineAsCodeAnnotations(doc.metadata?.annotations, deps);

// Handle PipelineRun resource with inline Pipeline definition
const pipelineSpec = doc.spec?.pipelineSpec;
if (is.truthy(pipelineSpec)) {
Expand Down Expand Up @@ -80,6 +85,74 @@ function getDeps(doc: TektonResource): PackageDependency[] {
return deps;
}

const taskAnnotation = regEx(/^pipelinesascode\.tekton\.dev\/task(-[0-9]+)?$/);

function addPipelineAsCodeAnnotations(
annotations: Record<string, string> | undefined | null,
deps: PackageDependency[],
): void {
if (is.nullOrUndefined(annotations)) {
return;
}

for (const [key, value] of Object.entries(annotations)) {
if (!taskAnnotation.test(key)) {
continue;
}

const tasks = value.replace('/]$/', '').replace('/^[/', '').split(',');
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
for (const task of tasks) {
const dep = getAnnotationDep(task.trim());
if (!dep) {
continue;
}
deps.push(dep);
}
}
}

const githubRelease = regEx(
/^(?<url>(?:(?:http|https):\/\/)?(?<path>(?:[^:/\s]+[:/])?(?<project>[^/\s]+\/[^/\s]+)))\/releases\/download\/(?<currentValue>.+)\/(?<subdir>[^?\s]*)$/,
);

const gitUrl = regEx(
/^(?<url>(?:(?:http|https):\/\/)?(?<path>(?:[^:/\s]+[:/])?(?<project>[^/\s]+\/[^/\s]+)))(?:\/raw)?\/(?<currentValue>.+?)\/(?<subdir>[^?\s]*)$/,
);

function getAnnotationDep(url: string): PackageDependency | null {
const dep: PackageDependency = {};
dep.depType = 'tekton-annotation';

let match = githubRelease.exec(url);

if (match?.groups) {
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
dep.datasource = GithubReleasesDatasource.id;

dep.depName = match?.groups?.path;
dep.packageName = match?.groups?.project;
dep.currentValue = match?.groups?.currentValue;
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
return dep;
}

match = gitUrl.exec(url);
if (match?.groups) {
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
dep.datasource = GitTagsDatasource.id;

dep.depName = match?.groups?.path.replace(
'raw.githubusercontent.com',
'github.com',
);
dep.packageName = match?.groups?.url.replace(
'raw.githubusercontent.com',
'github.com',
);
dep.currentValue = match?.groups?.currentValue;
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
return dep;
}

return null;
}

function addDep(ref: TektonBundle, deps: PackageDependency[]): void {
if (is.falsy(ref)) {
return;
Expand Down
3 changes: 2 additions & 1 deletion lib/modules/manager/tekton/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Category } from '../../../constants';
import { DockerDatasource } from '../../datasource/docker';
import { GitTagsDatasource } from '../../datasource/git-tags';
import { extractPackageFile } from './extract';

export const defaultConfig = {
Expand All @@ -8,6 +9,6 @@ export const defaultConfig = {

export const categories: Category[] = ['ci', 'cd'];

export const supportedDatasources = [DockerDatasource.id];
export const supportedDatasources = [DockerDatasource.id, GitTagsDatasource.id];

export { extractPackageFile };
11 changes: 10 additions & 1 deletion lib/modules/manager/tekton/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@ They can be created directly as a Kubernetes resource with standard tools like `
Tasks and Pipeline definitions can also live outside the Kubernetes cluster and get fetched by Tekton when needed, this approach relies on Tekton resource references rather than the resource definition.
The `tekton` manager focuses on providing updates to Tekton resource references.

Right now, Renovate's Tekton manager only supports references that are [Bundles](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/).
Right now, Renovate's Tekton manager supports references that are [Bundles](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/) and [PipelinesAsCode](https://pipelinesascode.com) with [remote http url resolver](https://pipelinesascode.com/docs/guide/resolver/#remote-http-url).
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
Read the [Tekton Pipeline remote resolution docs](https://tekton.dev/docs/pipelines/resolution/) for the different kinds of Tekton references and their corresponding resolvers.

### Using a PipelinesAsCode remote url reference
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved

By specifying the annotation with a remote task based on the recommended way using [git based versioning](https://github.com/tektoncd/community/blob/main/teps/0115-tekton-catalog-git-based-versioning.md).
rarkins marked this conversation as resolved.
Show resolved Hide resolved

```yaml
fabian-heib marked this conversation as resolved.
Show resolved Hide resolved
annotations:
pipelinesascode.tekton.dev/task: 'https://github.com/foo/bar/raw/v0.0.1/tasks/task/task.yaml'
```

### Using a Tekton Bundle reference

There are three ways to use a Tekton Bundle reference:
Expand Down
3 changes: 3 additions & 0 deletions lib/modules/manager/tekton/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export interface TektonResource {
spec: TektonResourceSpec;
items?: TektonResource[];
metadata?: {
annotations: Record<string, string>;
};
}

export interface TektonResourceSpec {
Expand Down