Skip to content

Commit

Permalink
Merge pull request #8 from frontegg/FR-18385-add-changelog-md-to-publ…
Browse files Browse the repository at this point in the history
…ic-openapi-repo

[FR-18385] add release workflow
  • Loading branch information
yossi-frontegg authored Nov 12, 2024
2 parents b1e530a + d8ffe69 commit 508592d
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 0 deletions.
53 changes: 53 additions & 0 deletions .github/actions/release/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Create Release
inputs:
npm_token:
description: 'Npm Token'
required: true
GH_ACCESS_TOKEN:
description: 'Github access token'
required: true
GH_USERNAME:
description: 'Github username'
required: true

runs:
using: 'composite'
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
path: current

- uses: actions/setup-node@v3
with:
node-version: 18

- name: Cache node modules
uses: actions/cache@v3
env:
cache-name: cache-node-modules
with:
path: ./node_modules
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Setup npmrc
working-directory: current
run: echo "//registry.npmjs.org/:_authToken=${{ inputs.npm_token }}" > .npmrc
shell: bash
- name: Install node dependencies
working-directory: current
run: npm install
shell: bash
- name: Install NPM Dependencies
run: npm install @octokit/[email protected] semver handlebars
shell: bash
- name: Create Release
run: node ci/release.js "${GH_ACCESS_TOKEN}" "${GH_USERNAME}"
shell: bash
env:
GH_ACCESS_TOKEN: ${{ inputs.GH_ACCESS_TOKEN }}
GH_USERNAME: ${{ inputs.GH_USERNAME }}
21 changes: 21 additions & 0 deletions .github/workflows/master-push.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Main Pipeline
on:
workflow_dispatch:
push:
branches:
- master
env:
CI: true
jobs:
release:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout codes
uses: actions/checkout@v3
- name: Create Release
uses: ./.github/actions/release
with:
npm_token: ${{ secrets.NPM_TOKEN }}
GH_ACCESS_TOKEN: ${{ secrets.GH_REPOSITORY_ADMIN_TOKEN }}
GH_USERNAME: ${{ secrets.GH_USERNAME }}
165 changes: 165 additions & 0 deletions ci/release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
const {execSync} = require('child_process');
const path = require('path');
const fs = require('fs');
const semver = require('semver');
const {Octokit} = require('@octokit/core');
const Handlebars = require('handlebars');

const GH_TOKEN = process.argv[2] ? process.argv[2] : process.env.GH_ACCESS_TOKEN;
const GH_USER = process.argv[3] ? process.argv[3] : 'x-access-token';

const githubApi = new Octokit({auth: GH_TOKEN});
const repoName = 'openapi-public';
const latestTagDirectory = path.join(__dirname, '../', 'temp', repoName);
const tempDirectory = path.join(__dirname, '../', 'temp');
const openapisFolder = path.join('/');
const latestOpenAPIsFolder = path.join(__dirname, '../', openapisFolder);

async function release() {
console.log('Checking out latest version tag');
const latestTag = await cloneAndCheckoutLatestTag();
console.log('Latest version tag:', latestTag);
console.log('Running diffs between current `master` OpenAPIs and latest version tag');
const {newEndpoints, missingEndpoints, deprecatedEndpoints} = await createDiffs();
if (newEndpoints.length || missingEndpoints.length || deprecatedEndpoints.length) {
const releaseType = determineReleaseType(missingEndpoints, deprecatedEndpoints);
const newVersion = increaseVersion(latestTag, releaseType);
console.log('Changes found, will create a new release', releaseType, newVersion);
const releaseBody = generateReleaseDescription(newEndpoints, missingEndpoints, deprecatedEndpoints);
await githubApi.request('POST /repos/{owner}/{repo}/releases', {
owner: 'frontegg',
repo: repoName,
tag_name: newVersion,
target_commitish: 'master',
name: newVersion,
body: releaseBody,
draft: false,
prerelease: false,
generate_release_notes: false,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
},
});
console.log('Release created successfully!');
} else {
console.log('No changes found, will skip release');
}
await clean();
}

async function cloneAndCheckoutLatestTag() {
try {
fs.rmdirSync(latestTagDirectory, {recursive: true});
} catch (e) {}
try {
fs.mkdirSync(latestTagDirectory, {recursive: true});
} catch (e) {}
execSync(`git clone https://${GH_USER}:${GH_TOKEN}@github.com/frontegg/${repoName}.git ${latestTagDirectory}`);
const latestTag = execSync('git describe --tags --abbrev=0').toString().trim();
execSync(`git checkout ${latestTag}`, {cwd: latestTagDirectory});
return latestTag;
}

async function listOpenAPIs() {
return ['agent.json', 'entitlements.json', 'identity.json', 'scim.json', 'sso.json', 'tenants.json'];
}

async function createDiffs() {
const latestOpenAPIs = await listOpenAPIs(latestOpenAPIsFolder);
try {
fs.mkdirSync(path.join(tempDirectory, 'diffs'), {recursive: true});
} catch (e) {}
const totalNewEndpoints = [];
const totalMissingEndpoints = [];
const totalDeprecatedEndpoints = [];
for (const openapi of latestOpenAPIs) {
const execCommand = `docker run -d \
-v ${path.join(__dirname, '../')}:/specs \
openapitools/openapi-diff:latest ${path.join(
'/specs',
'temp',
repoName,
openapisFolder,
openapi,
)} ${path.join('/specs', openapisFolder, openapi)} --json /specs/temp/diffs/${openapi}`;
execSync(execCommand);
const diffFilePath = path.join(__dirname, '../', 'temp/diffs', openapi);
await waitForDiffFileToGenerate(diffFilePath);
const {newEndpoints, missingEndpoints, deprecatedEndpoints} = JSON.parse(fs.readFileSync(diffFilePath).toString());
totalNewEndpoints.push(...newEndpoints);
totalMissingEndpoints.push(...missingEndpoints);
totalDeprecatedEndpoints.push(...deprecatedEndpoints);
}

return {
newEndpoints: totalNewEndpoints,
missingEndpoints: totalMissingEndpoints,
deprecatedEndpoints: totalDeprecatedEndpoints,
};
}

async function clean() {
fs.rmdirSync(tempDirectory, {recursive: true});
}

function determineReleaseType(missingEndpoints, deprecatedEndpoints) {
if (missingEndpoints.length) {
return 'major';
}

if (deprecatedEndpoints.length) {
return 'minor';
}

return 'patch';
}

function increaseVersion(latestVersion, releaseType) {
return `v${semver.inc(latestVersion, releaseType)}`;
}

function generateReleaseDescription(newEndpoints, missingEndpoints, deprecatedEndpoints) {
return Handlebars.compile(hbReleaseTemplate)({newEndpoints, missingEndpoints, deprecatedEndpoints});
}

async function waitForDiffFileToGenerate(path) {
const promise = new Promise((resolve) => {
const interval = setInterval(() => {
const exist = fs.existsSync(path);
if (exist) {
try {
JSON.parse(fs.readFileSync(path).toString());
resolve();
clearInterval(interval);
} catch (e) {}
}
}, 100);
});

await promise;
}

release();

const hbReleaseTemplate = `
{{#if newEndpoints.length}}
## New Endpoints
{{#each newEndpoints}}
{{method}} {{pathUrl}}
{{/each}}
{{/if}}
{{#if deprecatedEndpoints.length}}
## Deprecated Endpoints
{{#each deprecatedEndpoints}}
{{method}} {{pathUrl}}
{{/each}}
{{/if}}
{{#if missingEndpoints.length}}
## Removed Endpoints
{{#each missingEndpoints}}
{{method}} {{pathUrl}}
{{/each}}
{{/if}}
`;

0 comments on commit 508592d

Please sign in to comment.