Skip to content

Commit 72f11e4

Browse files
committed
ops(ci): conventional-commits based release versions
- added enforcing of conventional commits - project version is now set by axion-release gradle plugin, configured to extract the version based on the commit history see https://axion-release-plugin.readthedocs.io/en/latest/
1 parent 2e9858d commit 72f11e4

File tree

2 files changed

+272
-0
lines changed
  • .github/actions
    • detect-modified-projects/dist
    • execute-gradle-tasks-on-projects/dist

2 files changed

+272
-0
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"use strict";
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
var desc = Object.getOwnPropertyDescriptor(m, k);
5+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6+
desc = { enumerable: true, get: function() { return m[k]; } };
7+
}
8+
Object.defineProperty(o, k2, desc);
9+
}) : (function(o, m, k, k2) {
10+
if (k2 === undefined) k2 = k;
11+
o[k2] = m[k];
12+
}));
13+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14+
Object.defineProperty(o, "default", { enumerable: true, value: v });
15+
}) : function(o, v) {
16+
o["default"] = v;
17+
});
18+
var __importStar = (this && this.__importStar) || function (mod) {
19+
if (mod && mod.__esModule) return mod;
20+
var result = {};
21+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22+
__setModuleDefault(result, mod);
23+
return result;
24+
};
25+
Object.defineProperty(exports, "__esModule", { value: true });
26+
const child_process_1 = require("child_process");
27+
const core = __importStar(require("@actions/core"));
28+
function sh(cmd, opts = {}) {
29+
try {
30+
return (0, child_process_1.execSync)(cmd, { encoding: 'utf-8', stdio: opts.silent ? ['ignore', 'pipe', 'pipe'] : 'pipe' }).trim();
31+
}
32+
catch (e) {
33+
if (!opts.silent)
34+
core.debug(`Command failed: ${cmd}\n${String(e)}`);
35+
throw e;
36+
}
37+
}
38+
function trySh(cmd, opts = {}) {
39+
try {
40+
return sh(cmd, opts);
41+
}
42+
catch {
43+
return '';
44+
}
45+
}
46+
function isShallowRepo() {
47+
const out = trySh('git rev-parse --is-shallow-repository', { silent: true });
48+
return out === 'true';
49+
}
50+
function ensureHistoryAndTags() {
51+
// Detect shallow/non-shallow
52+
let isShallow;
53+
try {
54+
const out = (0, child_process_1.execSync)('git rev-parse --is-shallow-repository', { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
55+
isShallow = out === 'true';
56+
}
57+
catch {
58+
// If the command isn't supported (very old git), assume not shallow
59+
isShallow = false;
60+
}
61+
core.info(`Repo shallow: ${isShallow}`);
62+
if (isShallow) {
63+
// Shallow checkout → unshallow and fetch tags
64+
core.info('Fetching to unshallow repository and include tags…');
65+
(0, child_process_1.execSync)('git fetch --unshallow --tags --force', { encoding: 'utf-8' });
66+
}
67+
else {
68+
// Already complete → just refresh tags and prune
69+
core.info('Repository already complete; fetching tags and pruning…');
70+
(0, child_process_1.execSync)('git fetch --tags --force --prune', { encoding: 'utf-8' });
71+
}
72+
}
73+
/**
74+
* Determine a sensible base for diff:
75+
* - On pull_request events: origin/<base_branch>
76+
* - On push events: HEAD~1 (previous commit on same branch) if exists
77+
* - Fallback: merge-base with origin/main (adjust default if needed)
78+
*/
79+
function resolveBaseRef() {
80+
const eventName = process.env.GITHUB_EVENT_NAME || '';
81+
const prBase = process.env.GITHUB_BASE_REF; // set on pull_request events
82+
if (eventName.startsWith('pull_request') && prBase) {
83+
core.info(`PR build detected. Using origin/${prBase} as diff base`);
84+
// Ensure we have the PR base
85+
trySh(`git fetch origin ${prBase} --force`, { silent: true });
86+
return `origin/${prBase}`;
87+
}
88+
// Push builds: previous commit if available
89+
const prev = trySh('git rev-parse HEAD~1', { silent: true });
90+
if (prev) {
91+
core.info('Push build detected. Using HEAD~1 as diff base');
92+
return prev;
93+
}
94+
// Fallback: merge-base with origin/main (change "main" if your default is different)
95+
core.info('Fallback diff base: merge-base with origin/main');
96+
trySh('git fetch origin main --force', { silent: true });
97+
const mergeBase = trySh('git merge-base HEAD origin/main', { silent: true });
98+
return mergeBase || 'HEAD';
99+
}
100+
function run() {
101+
try {
102+
const subprojectPrefixes = (core.getInput('project_prefixes') || '')
103+
.split(',')
104+
.map(s => s.trim())
105+
.filter(Boolean);
106+
const requiredProjects = (core.getInput('required_projects') || '')
107+
.split(',')
108+
.map(s => s.trim())
109+
.filter(Boolean);
110+
core.debug('Ensuring full history and tags…');
111+
ensureHistoryAndTags();
112+
const githubSha = process.env.GITHUB_SHA;
113+
if (!githubSha) {
114+
core.setFailed('GITHUB_SHA not set');
115+
return;
116+
}
117+
const base = resolveBaseRef();
118+
const diffCmd = `git diff --name-only ${base}..${githubSha}`;
119+
core.debug(`Executing: ${diffCmd}`);
120+
core.debug(`Git Status: ${(0, child_process_1.execSync)(`git status`, { encoding: 'utf-8' }).trim()}`);
121+
core.debug(`SHA Exists: ${(0, child_process_1.execSync)(`git cat-file -e ${githubSha}`, { encoding: 'utf-8' }).trim()}`);
122+
let modifiedProjects = (0, child_process_1.execSync)(diffCmd, { encoding: 'utf8' });
123+
core.debug("Modified Projects:" + modifiedProjects);
124+
core.debug("Required Projects:" + requiredProjects);
125+
if (modifiedProjects.includes('buildSrc/') && !modifiedProjects.includes('ktor-')) {
126+
core.debug("only buildSrc has modified");
127+
modifiedProjects = "buildSrc";
128+
}
129+
else {
130+
const subprojectPrefixesPattern = subprojectPrefixes.join("|");
131+
core.debug("subprojectPrefixesPattern: " + subprojectPrefixesPattern);
132+
const regex = subprojectPrefixes.length > 0
133+
? new RegExp(`^(${subprojectPrefixesPattern})`)
134+
: null;
135+
let modifiedProjectsArray = modifiedProjects.split('\n')
136+
.filter(line => {
137+
return regex ? regex.test(line) : true;
138+
})
139+
.map(line => line.split('/', 1)[0])
140+
.sort()
141+
.filter((value, index, self) => self.indexOf(value) === index);
142+
modifiedProjects = [...new Set(modifiedProjectsArray.concat(requiredProjects))].join(',');
143+
}
144+
if (modifiedProjects) {
145+
core.info(`Modified subprojects including required projects: ${modifiedProjects}`);
146+
core.setOutput('modified_projects', modifiedProjects);
147+
}
148+
else {
149+
core.info("No modified subprojects");
150+
}
151+
}
152+
catch (error) {
153+
core.setFailed(`Action failed with error: ${error}`);
154+
}
155+
}
156+
run();
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
"use strict";
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
var desc = Object.getOwnPropertyDescriptor(m, k);
5+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6+
desc = { enumerable: true, get: function() { return m[k]; } };
7+
}
8+
Object.defineProperty(o, k2, desc);
9+
}) : (function(o, m, k, k2) {
10+
if (k2 === undefined) k2 = k;
11+
o[k2] = m[k];
12+
}));
13+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14+
Object.defineProperty(o, "default", { enumerable: true, value: v });
15+
}) : function(o, v) {
16+
o["default"] = v;
17+
});
18+
var __importStar = (this && this.__importStar) || function (mod) {
19+
if (mod && mod.__esModule) return mod;
20+
var result = {};
21+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22+
__setModuleDefault(result, mod);
23+
return result;
24+
};
25+
Object.defineProperty(exports, "__esModule", { value: true });
26+
const core = __importStar(require("@actions/core"));
27+
const child_process_1 = require("child_process");
28+
class StringBuilder {
29+
constructor() {
30+
this._parts = [];
31+
}
32+
append(value) {
33+
this._parts.push(value);
34+
}
35+
toString() {
36+
return this._parts.join("");
37+
}
38+
}
39+
async function run() {
40+
var _a, _b;
41+
try {
42+
let projects = core.getInput('projects');
43+
let tasks = core.getInput('tasks');
44+
let executeOnRootAnyway = (_b = ((_a = core.getInput('execute_on_root_anyway', {
45+
trimWhitespace: true,
46+
})) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'true') !== null && _b !== void 0 ? _b : false;
47+
let rootProjectTask = core.getInput('parent_project_task', {
48+
required: false
49+
});
50+
core.debug(`Projects: '${projects}'`);
51+
core.debug(`Tasks: '${tasks}'`);
52+
core.debug(`Root project Task: '${rootProjectTask}'`);
53+
const taskArr = tasks.split(',').filter((p) => p.trim() !== '');
54+
core.debug("Task array: " + taskArr);
55+
let gradleProjectsTasks;
56+
if (projects === 'buildSrc') {
57+
core.info(`only buildSrc has changed, setting gradleProjectsTasks to ${tasks.replace(",", " ")}`);
58+
gradleProjectsTasks = `${tasks.replace(",", " ")} `;
59+
}
60+
else {
61+
const projArr = projects.split(',').filter((p) => p.trim() !== '');
62+
core.debug(`building gradleProjectsTasks with projects: ${projArr} and tasks: ${taskArr}`);
63+
if (taskArr.length === 0 && !rootProjectTask) {
64+
core.info("No tasks provided, skipping");
65+
return;
66+
}
67+
if (projArr.length === 0 && !executeOnRootAnyway) {
68+
core.info("No projects to build, skipping");
69+
return;
70+
}
71+
if (projArr.length > 0) {
72+
gradleProjectsTasks = projArr.reduce((acc1, proj) => {
73+
return acc1 + taskArr.reduce((acc2, task) => {
74+
return acc2 + `:${proj}:${task} `;
75+
}, '');
76+
}, '');
77+
}
78+
else {
79+
gradleProjectsTasks = taskArr.reduce((acc1, task) => {
80+
return acc1 + `${task} `;
81+
}, '');
82+
}
83+
}
84+
if (rootProjectTask) {
85+
core.debug(`Adding root project task: ${rootProjectTask} to command`);
86+
gradleProjectsTasks += rootProjectTask;
87+
}
88+
const gradleCommand = `./gradlew --stacktrace ${gradleProjectsTasks.trim()}`;
89+
core.info(`Executing: ${gradleCommand}`);
90+
const gradleArgs = gradleCommand.split(' ');
91+
const gradleChild = (0, child_process_1.spawn)(gradleArgs[0], gradleArgs.slice(1));
92+
const processPromise = new Promise((resolve, reject) => {
93+
let gradleOutputBuilder = new StringBuilder();
94+
gradleChild.stdout.on('data', (data) => {
95+
gradleOutputBuilder.append(data.toString());
96+
core.info(data.toString());
97+
});
98+
gradleChild.stderr.on('data', (data) => {
99+
core.error(data.toString());
100+
});
101+
gradleChild.on('exit', (code, signal) => {
102+
if (code !== 0) {
103+
reject(new Error(`Gradle exited with code ${code} due to signal ${signal}`));
104+
}
105+
else {
106+
resolve(gradleOutputBuilder.toString());
107+
}
108+
});
109+
});
110+
core.setOutput('gradle_output', await processPromise);
111+
}
112+
catch (error) {
113+
core.setFailed(error.message);
114+
}
115+
}
116+
run();

0 commit comments

Comments
 (0)