Skip to content

Commit 39d2357

Browse files
committed
Merge branch 'main' into use-cp-nx-plugin
# Conflicts: # package.json
2 parents 0049a64 + c7d314e commit 39d2357

File tree

24 files changed

+368
-58
lines changed

24 files changed

+368
-58
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Code PushUp
2+
description: Minimalist GitHub Action that executes Code PushUp using local @code-pushup/ci source code
3+
4+
inputs:
5+
token:
6+
description: GitHub token for API access
7+
required: true
8+
default: ${{ github.token }}
9+
10+
runs:
11+
using: composite
12+
steps:
13+
- name: Run Node script
14+
run: npx tsx .github/actions/code-pushup/src/runner.ts
15+
shell: bash
16+
env:
17+
TSX_TSCONFIG_PATH: .github/actions/code-pushup/tsconfig.json
18+
GH_TOKEN: ${{ inputs.token }}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "@code-pushup/local-action",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"description": "Minimalist GitHub Action that executes Code PushUp using local @code-pushup/ci source code for testing CI changes"
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "local-action",
3+
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": ".github/actions/code-pushup/src",
5+
"projectType": "application",
6+
"targets": {},
7+
"tags": ["type:app"]
8+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import * as core from '@actions/core';
2+
import * as github from '@actions/github';
3+
import type { WebhookPayload } from '@actions/github/lib/interfaces';
4+
import type { components } from '@octokit/openapi-types';
5+
import {
6+
type Comment,
7+
type GitBranch,
8+
type Options,
9+
type ProviderAPIClient,
10+
type SourceFileIssue,
11+
runInCI,
12+
} from '@code-pushup/ci';
13+
import { CODE_PUSHUP_UNICODE_LOGO } from '@code-pushup/utils';
14+
15+
type GitHubRefs = {
16+
head: GitBranch;
17+
base?: GitBranch;
18+
};
19+
20+
type PullRequestPayload = NonNullable<WebhookPayload['pull_request']> &
21+
components['schemas']['pull-request-minimal'];
22+
23+
const LOG_PREFIX = '[Code PushUp GitHub action]';
24+
25+
const MAX_COMMENT_CHARS = 65_536;
26+
27+
function convertComment(
28+
comment: Pick<components['schemas']['issue-comment'], 'id' | 'body' | 'url'>,
29+
): Comment {
30+
const { id, body = '', url } = comment;
31+
return { id, body, url };
32+
}
33+
34+
function isPullRequest(
35+
payload: WebhookPayload['pull_request'],
36+
): payload is PullRequestPayload {
37+
return payload != null;
38+
}
39+
40+
function parseBranchRef({ ref, sha }: GitBranch): GitBranch {
41+
return {
42+
ref: ref.split('/').at(-1) ?? ref,
43+
sha,
44+
};
45+
}
46+
47+
function parseGitRefs(): GitHubRefs {
48+
if (isPullRequest(github.context.payload.pull_request)) {
49+
const { head, base } = github.context.payload.pull_request;
50+
return { head: parseBranchRef(head), base: parseBranchRef(base) };
51+
}
52+
return { head: parseBranchRef(github.context) };
53+
}
54+
55+
function createAnnotationsFromIssues(issues: SourceFileIssue[]): void {
56+
if (issues.length > 0) {
57+
core.info(`Creating annotations for ${issues.length} issues:`);
58+
}
59+
// eslint-disable-next-line functional/no-loop-statements
60+
for (const issue of issues) {
61+
const message = issue.message;
62+
const properties: core.AnnotationProperties = {
63+
title: `${CODE_PUSHUP_UNICODE_LOGO} ${issue.plugin.title} | ${issue.audit.title}`,
64+
file: issue.source.file,
65+
startLine: issue.source.position?.startLine,
66+
startColumn: issue.source.position?.startColumn,
67+
endLine: issue.source.position?.endLine,
68+
endColumn: issue.source.position?.endColumn,
69+
};
70+
switch (issue.severity) {
71+
case 'error':
72+
core.error(message, properties);
73+
break;
74+
case 'warning':
75+
core.warning(message, properties);
76+
break;
77+
case 'info':
78+
core.notice(message, properties);
79+
break;
80+
}
81+
}
82+
}
83+
84+
function createGitHubApiClient(): ProviderAPIClient {
85+
const token = process.env.GH_TOKEN;
86+
87+
if (!token) {
88+
throw new Error('No GitHub token found');
89+
}
90+
91+
const octokit = github.getOctokit(token);
92+
93+
return {
94+
maxCommentChars: MAX_COMMENT_CHARS,
95+
96+
listComments: async (): Promise<Comment[]> => {
97+
const comments = await octokit.paginate(
98+
octokit.rest.issues.listComments,
99+
{
100+
...github.context.repo,
101+
issue_number: github.context.issue.number,
102+
},
103+
);
104+
return comments.map(convertComment);
105+
},
106+
107+
createComment: async (body: string): Promise<Comment> => {
108+
const { data } = await octokit.rest.issues.createComment({
109+
...github.context.repo,
110+
issue_number: github.context.issue.number,
111+
body,
112+
});
113+
return convertComment(data);
114+
},
115+
116+
updateComment: async (id: number, body: string): Promise<Comment> => {
117+
const { data } = await octokit.rest.issues.updateComment({
118+
...github.context.repo,
119+
comment_id: id,
120+
body,
121+
});
122+
return convertComment(data);
123+
},
124+
};
125+
}
126+
127+
async function run(): Promise<void> {
128+
try {
129+
const options: Options = {
130+
bin: 'npx nx code-pushup --nx-bail --',
131+
};
132+
133+
const gitRefs = parseGitRefs();
134+
135+
const apiClient = createGitHubApiClient();
136+
137+
const result = await runInCI(gitRefs, apiClient, options);
138+
139+
const issues =
140+
result.mode === 'standalone'
141+
? (result.newIssues ?? [])
142+
: result.projects.flatMap(project => project.newIssues ?? []);
143+
144+
if (issues.length > 0) {
145+
core.info(
146+
`Found ${issues.length} new issues, creating GitHub annotations`,
147+
);
148+
createAnnotationsFromIssues(issues);
149+
}
150+
151+
core.info(`${LOG_PREFIX} Finished running successfully`);
152+
} catch (error) {
153+
const message = error instanceof Error ? error.message : String(error);
154+
core.error(`${LOG_PREFIX} Failed: ${message}`);
155+
core.setFailed(message);
156+
}
157+
}
158+
159+
await run();
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"include": ["src/**/*"]
4+
}

.github/workflows/code-pushup-fork.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ jobs:
3737
- name: Install dependencies
3838
run: npm ci
3939
- name: Run Code PushUp action
40-
uses: code-pushup/github-action@v0
40+
uses: ./.github/actions/code-pushup
4141
with:
42-
bin: npx nx code-pushup --nx-bail --
42+
token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/code-pushup.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ jobs:
3939
- name: Install dependencies
4040
run: npm ci
4141
- name: Run Code PushUp action
42-
uses: code-pushup/github-action@v0
42+
uses: ./.github/actions/code-pushup
4343
with:
44-
bin: npx nx code-pushup --nx-bail --
44+
token: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 0.79.1 (2025-09-04)
2+
3+
### 🩹 Fixes
4+
5+
- **nx-plugin:** process output argument ([#1105](https://github.com/code-pushup/cli/pull/1105))
6+
7+
### ❤️ Thank You
8+
9+
- Michael Hladky @BioPhoton
10+
111
## 0.79.0 (2025-09-03)
212

313
### 🚀 Features

nx.json

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
"$schema": "./node_modules/nx/schemas/nx-schema.json",
33
"namedInputs": {
44
"default": ["{projectRoot}/**/*", "sharedGlobals"],
5+
"os": [
6+
{
7+
"runtime": "node -e \"console.log(require('os').platform())\""
8+
}
9+
],
510
"production": [
611
"default",
712
"!{projectRoot}/README.md",
@@ -22,25 +27,22 @@
2227
"!{workspaceRoot}/**/(*.)coverage/**/*"
2328
],
2429
"test-vitest-inputs": [
25-
"default",
30+
"os",
2631
{
2732
"externalDependencies": ["vitest"]
2833
}
2934
],
3035
"lint-eslint-inputs": [
31-
"default",
3236
{
3337
"externalDependencies": ["eslint"]
3438
}
3539
],
3640
"typecheck-typescript-inputs": [
37-
"default",
3841
{
3942
"externalDependencies": ["typescript"]
4043
}
4144
],
4245
"code-pushup-inputs": [
43-
"default",
4446
{
4547
"env": "NODE_OPTIONS"
4648
},
@@ -49,9 +51,6 @@
4951
}
5052
],
5153
"sharedGlobals": [
52-
{
53-
"runtime": "node -e \"console.log(require('os').platform())\""
54-
},
5554
{
5655
"runtime": "node -v"
5756
},
@@ -63,7 +62,7 @@
6362
"targetDefaults": {
6463
"lint": {
6564
"dependsOn": ["eslint-formatter-multi:build"],
66-
"inputs": ["lint-eslint-inputs"],
65+
"inputs": ["default", "lint-eslint-inputs"],
6766
"outputs": ["{projectRoot}/.eslint/**/*"],
6867
"cache": true,
6968
"executor": "nx:run-commands",
@@ -98,6 +97,7 @@
9897
},
9998
"unit-test": {
10099
"cache": true,
100+
"inputs": ["default", "test-vitest-inputs"],
101101
"outputs": [
102102
"{workspaceRoot}/coverage/{projectName}/unit-tests/lcov.info"
103103
],
@@ -111,6 +111,7 @@
111111
},
112112
"int-test": {
113113
"cache": true,
114+
"inputs": ["default", "test-vitest-inputs"],
114115
"outputs": ["{workspaceRoot}/coverage/{projectName}/int-tests/lcov.info"],
115116
"executor": "@nx/vite:test",
116117
"options": {
@@ -121,16 +122,16 @@
121122
}
122123
},
123124
"e2e": {
124-
"dependsOn": ["^build"],
125-
"inputs": ["default"],
126-
"cache": true
125+
"cache": true,
126+
"inputs": ["default", "test-vitest-inputs"],
127+
"dependsOn": ["^build"]
127128
},
128129
"nxv-pkg-install": {
129130
"parallelism": false
130131
},
131132
"@nx/vite:test": {
132133
"cache": true,
133-
"inputs": ["test-vitest-inputs"],
134+
"inputs": ["default", "test-vitest-inputs"],
134135
"options": {
135136
"passWithNoTests": true,
136137
"watch": false
@@ -161,7 +162,7 @@
161162
},
162163
"code-pushup-coverage": {
163164
"cache": true,
164-
"inputs": ["code-pushup-inputs", "test-vitest-inputs"],
165+
"inputs": ["default", "code-pushup-inputs"],
165166
"outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"],
166167
"executor": "nx:run-commands",
167168
"dependsOn": ["*-test"],
@@ -184,7 +185,7 @@
184185
},
185186
"code-pushup-eslint": {
186187
"cache": true,
187-
"inputs": ["code-pushup-inputs", "lint-eslint-inputs"],
188+
"inputs": ["default", "code-pushup-inputs", "lint-eslint-inputs"],
188189
"outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"],
189190
"executor": "nx:run-commands",
190191
"options": {
@@ -230,7 +231,7 @@
230231
},
231232
"code-pushup-lighthouse": {
232233
"cache": true,
233-
"inputs": ["code-pushup-inputs", "production", "^production"],
234+
"inputs": ["production", "^production", "code-pushup-inputs"],
234235
"outputs": ["{projectRoot}/.code-pushup/lighthouse/runner-output.json"],
235236
"executor": "nx:run-commands",
236237
"options": {
@@ -252,7 +253,11 @@
252253
},
253254
"code-pushup-jsdocs": {
254255
"cache": true,
255-
"inputs": ["code-pushup-inputs", "typecheck-typescript-inputs"],
256+
"inputs": [
257+
"default",
258+
"code-pushup-inputs",
259+
"typecheck-typescript-inputs"
260+
],
256261
"outputs": ["{projectRoot}/.code-pushup/jsdocs/runner-output.json"],
257262
"executor": "nx:run-commands",
258263
"options": {
@@ -274,7 +279,11 @@
274279
},
275280
"code-pushup-typescript": {
276281
"cache": true,
277-
"inputs": ["code-pushup-inputs", "typecheck-typescript-inputs"],
282+
"inputs": [
283+
"default",
284+
"code-pushup-inputs",
285+
"typecheck-typescript-inputs"
286+
],
278287
"outputs": ["{projectRoot}/.code-pushup/typescript/runner-output.json"],
279288
"executor": "nx:run-commands",
280289
"options": {

0 commit comments

Comments
 (0)