- [x] change init to create `createNodes` instead - [x] unit tests - [x] test-ci - [x] test on windows - [x] help metadata - [x] external nodes TODO: - add publish executor? - publish to maven central? <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> currently, it uses [project report plugin](https://docs.gradle.org/current/userguide/project_report_plugin.html). - pro: no need to maintain this plugin - con: this plugin gives limited information ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> change the project report plugin to @nxn/gradle/plugin-v1 now the @nx/gradle plugin will use project graph plugin (dev.nx.gradle.project-graph) created in this pr. this plugin will create json file that is exactly what nx project grpah expected. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
134 lines
3.8 KiB
TypeScript
134 lines
3.8 KiB
TypeScript
import axios from 'axios';
|
|
import * as fs from 'fs';
|
|
import * as FormData from 'form-data';
|
|
|
|
function parseArgs() {
|
|
const args = process.argv.slice(2);
|
|
const result: Record<string, string> = {};
|
|
args.forEach((arg) => {
|
|
const [key, value] = arg.replace(/^--/, '').split('=');
|
|
result[key] = value;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
async function publishToMavenApi(
|
|
username: string,
|
|
password: string,
|
|
deploymentZipPath = 'deployment.zip'
|
|
) {
|
|
const token = Buffer.from(`${username}:${password}`).toString('base64');
|
|
console.log(`📦 Publishing to Maven Central...`);
|
|
|
|
const url = 'https://central.sonatype.com/api/v1/publisher/upload';
|
|
const form = new FormData();
|
|
form.append('bundle', fs.createReadStream(deploymentZipPath));
|
|
|
|
let uploadId: string;
|
|
try {
|
|
const response = await axios.post(url, form, {
|
|
headers: {
|
|
Authorization: `Basic ${token}`,
|
|
...form.getHeaders(),
|
|
},
|
|
});
|
|
uploadId = response.data.toString().trim();
|
|
console.log(`✅ Upload ID: ${uploadId}`);
|
|
} catch (err: any) {
|
|
console.error('🚫 Upload failed:', err.response?.data || err.message);
|
|
process.exit(1);
|
|
}
|
|
|
|
let currentStatus = await getUploadStatus(uploadId, token);
|
|
if (['PENDING', 'VALIDATING', 'PUBLISHING'].includes(currentStatus)) {
|
|
currentStatus = await retryUntilValidatedOrPublished(
|
|
currentStatus,
|
|
uploadId,
|
|
token
|
|
);
|
|
}
|
|
|
|
if (!['VALIDATED', 'PUBLISHED'].includes(currentStatus)) {
|
|
console.error(`🚫 Upload failed with final status: ${currentStatus}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`📦 Upload is ${currentStatus}, proceeding to deploy...`);
|
|
if (currentStatus === 'PUBLISHED') {
|
|
console.log('✅ Already published, skipping deployment.');
|
|
return;
|
|
}
|
|
|
|
const deployUrl = `https://central.sonatype.com/api/v1/publisher/deployment/${uploadId}`;
|
|
try {
|
|
const deployRes = await axios.post(deployUrl, null, {
|
|
headers: { Authorization: `Basic ${token}` },
|
|
});
|
|
console.log(`🚀 Deployment response: ${deployRes.data}`);
|
|
} catch (err: any) {
|
|
console.error('🚫 Deployment failed:', err.response?.data || err.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
async function getUploadStatus(
|
|
uploadId: string,
|
|
token: string
|
|
): Promise<string> {
|
|
const url = `https://central.sonatype.com/api/v1/publisher/status?id=${uploadId}`;
|
|
try {
|
|
const response = await axios.post(url, null, {
|
|
headers: { Authorization: `Basic ${token}` },
|
|
});
|
|
const state = response.data.deploymentState;
|
|
console.log(`📡 Current deployment state: ${state}`);
|
|
return state;
|
|
} catch (err: any) {
|
|
console.error(
|
|
'🚫 Failed to get status:',
|
|
err.response?.data || err.message
|
|
);
|
|
return 'FAILED';
|
|
}
|
|
}
|
|
|
|
async function retryUntilValidatedOrPublished(
|
|
currentStatus: string,
|
|
uploadId: string,
|
|
token: string,
|
|
retries = 10,
|
|
delay = 10_000
|
|
): Promise<string> {
|
|
for (let i = 0; i < retries; i++) {
|
|
console.log(`🔁 Checking status (attempt ${i + 1}/${retries})...`);
|
|
await sleep(delay);
|
|
currentStatus = await getUploadStatus(uploadId, token);
|
|
if (['VALIDATED', 'PUBLISHED', 'FAILED'].includes(currentStatus)) break;
|
|
}
|
|
return currentStatus;
|
|
}
|
|
|
|
function sleep(ms: number) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
// Entry
|
|
(async function main() {
|
|
let { username, password, deploymentZipPath } = parseArgs();
|
|
|
|
username = username || process.env.MAVEN_USERNAME;
|
|
password = password || process.env.MAVEN_PASSWORD;
|
|
|
|
if (!username || !password) {
|
|
console.error('❌ Missing MAVEN_USERNAME or MAVEN_PASSWORD');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!deploymentZipPath) {
|
|
console.error('❌ Missing required --deploymentZipPath argument');
|
|
process.exit(1);
|
|
}
|
|
|
|
await publishToMavenApi(username, password, deploymentZipPath);
|
|
})();
|