mirror of
https://github.com/grafana/grafana.git
synced 2025-01-09 23:53:25 -06:00
Chore: update changelog workflow (#90608)
* try integrating * pass tags * change section order * use better terminology * one more attempt * keep delimiters * attempt to patch changelog * quotes, bash quotes... * use proper content file * parens around date * time for a pr * first checkout, then create user * add latest input * git push * use square brackets * formatting * update release-pr * fix typo * try sparse checkout * fetch depth zero * clean up after changelog generator
This commit is contained in:
parent
8f54e3bfb7
commit
f8b092aba6
10
.github/workflows/actions/changelog/action.yml
vendored
10
.github/workflows/actions/changelog/action.yml
vendored
@ -1,13 +1,13 @@
|
||||
name: Changelog generator
|
||||
description: Generates and publishes a changelog for the given release version
|
||||
inputs:
|
||||
version:
|
||||
description: Version number
|
||||
target:
|
||||
description: Target tag, branch or commit hash for the changelog
|
||||
required: true
|
||||
prev_version:
|
||||
description: Previous version number
|
||||
previous:
|
||||
description: Previous tag, branch or commit hash to start changelog from
|
||||
required: false
|
||||
token:
|
||||
github_token:
|
||||
description: GitHub token with read/write access to all necessary repositories
|
||||
required: true
|
||||
output_file:
|
||||
|
56
.github/workflows/actions/changelog/index.js
vendored
56
.github/workflows/actions/changelog/index.js
vendored
@ -52,17 +52,20 @@ const getPreviousVersion = async (version) => {
|
||||
.filter((tag) => tag)
|
||||
.sort(semverCompare)
|
||||
.find((tag) => semverCompare(tag, semverParse(version)) > 0);
|
||||
return prev;
|
||||
if (!prev) {
|
||||
throw `Could not find previous git tag for ${version}`;
|
||||
}
|
||||
return prev[4];
|
||||
};
|
||||
|
||||
// A helper for Github GraphQL API endpoint
|
||||
const graphql = async (token, query, variables) => {
|
||||
const graphql = async (ghtoken, query, variables) => {
|
||||
const { env } = process;
|
||||
const results = await fetch('https://api.github.com/graphql', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
Authorization: `Bearer ${ghtoken}`,
|
||||
},
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
@ -76,7 +79,7 @@ const graphql = async (token, query, variables) => {
|
||||
// "commitish" items and get a list of PRs in between them.
|
||||
const getCommitishDate = async (name, owner, target) => {
|
||||
const result = await graphql(
|
||||
token,
|
||||
ghtoken,
|
||||
`
|
||||
query getCommitDate($owner: String!, $name: String!, $target: String!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
@ -96,9 +99,8 @@ const getCommitishDate = async (name, owner, target) => {
|
||||
// Using Github GraphQL API get a list of PRs between the two "commitish" items.
|
||||
// This resoves the "since" item's timestamp first and iterates over all PRs
|
||||
// till "target" using naïve pagination.
|
||||
const getHistory = async (name, owner, target, since) => {
|
||||
const sinceDate = await getCommitishDate(name, owner, since);
|
||||
LOG(`Fetching ${owner}/${name} PRs since ${since} (${sinceDate}) till ${target}`);
|
||||
const getHistory = async (name, owner, target, sinceDate) => {
|
||||
LOG(`Fetching ${owner}/${name} PRs since ${sinceDate} till ${target}`);
|
||||
const query = `
|
||||
query findCommitsWithAssociatedPullRequests(
|
||||
$name: String!
|
||||
@ -150,7 +152,7 @@ const getHistory = async (name, owner, target, since) => {
|
||||
let cursor;
|
||||
let nodes = [];
|
||||
for (;;) {
|
||||
const result = await graphql(token, query, {
|
||||
const result = await graphql(ghtoken, query, {
|
||||
name,
|
||||
owner,
|
||||
target,
|
||||
@ -173,11 +175,11 @@ const getHistory = async (name, owner, target, since) => {
|
||||
// feature, deprecation, breaking change and plugin fixes/enhancements).
|
||||
//
|
||||
// PR grouping relies on Github labels only, not on the PR contents.
|
||||
const getChangeLogItems = async (name, owner, from, to) => {
|
||||
const getChangeLogItems = async (name, owner, sinceDate, to) => {
|
||||
// check if a node contains a certain label
|
||||
const hasLabel = ({ labels }, label) => labels.nodes.some(({ name }) => name === label);
|
||||
// get all the PRs between the two "commitish" items
|
||||
const history = await getHistory(name, owner, to, from);
|
||||
const history = await getHistory(name, owner, to, sinceDate);
|
||||
|
||||
const items = history.flatMap((node) => {
|
||||
// discard PRs without a "changelog" label
|
||||
@ -216,20 +218,26 @@ const getChangeLogItems = async (name, owner, from, to) => {
|
||||
// ======================================================
|
||||
|
||||
LOG(`Changelog action started`);
|
||||
const version = process.argv[2] || process.env.INPUT_VERSION;
|
||||
LOG(`Target version: ${version}`);
|
||||
const prevVersion = process.argv[3] || process.env.INPUT_PREV_VERSION || (await getPreviousVersion(version));
|
||||
LOG(`Previous version: ${prevVersion}`);
|
||||
const token = process.env.GITHUB_TOKEN || process.env.INPUT_TOKEN;
|
||||
|
||||
if (!token) {
|
||||
throw 'GITHUB_TOKEN is not set and "token" input is empty';
|
||||
const ghtoken = process.env.GITHUB_TOKEN || process.env.INPUT_GITHUB_TOKEN;
|
||||
if (!ghtoken) {
|
||||
throw 'GITHUB_TOKEN is not set and "github_token" input is empty';
|
||||
}
|
||||
|
||||
const target = process.argv[2] || process.env.INPUT_TARGET;
|
||||
LOG(`Target tag/branch/commit: ${target}`);
|
||||
|
||||
const previous = process.argv[3] || process.env.INPUT_PREVIOUS || (await getPreviousVersion(target));
|
||||
|
||||
LOG(`Previous tag/commit: ${previous}`);
|
||||
|
||||
const sinceDate = await getCommitishDate('grafana', 'grafana', previous);
|
||||
LOG(`Previous tag/commit timestamp: ${sinceDate}`);
|
||||
|
||||
// Get all changelog items from Grafana OSS
|
||||
const oss = await getChangeLogItems('grafana', 'grafana', prevVersion, version);
|
||||
const oss = await getChangeLogItems('grafana', 'grafana', sinceDate, target);
|
||||
// Get all changelog items from Grafana Enterprise
|
||||
const entr = await getChangeLogItems('grafana-enterprise', 'grafana', prevVersion, version);
|
||||
const entr = await getChangeLogItems('grafana-enterprise', 'grafana', sinceDate, target);
|
||||
|
||||
LOG(`Found OSS PRs: ${oss.length}`);
|
||||
LOG(`Found Enterprise PRs: ${entr.length}`);
|
||||
@ -251,13 +259,10 @@ const changelog = [...oss, ...entr]
|
||||
return changelog;
|
||||
},
|
||||
{
|
||||
version,
|
||||
breaking: [],
|
||||
plugins: [],
|
||||
bugfixes: [],
|
||||
features: [],
|
||||
// looks like JS doesn't have a nicer way to format date as YYYY-MM-DD
|
||||
releaseDate: new Date().toISOString().split('T')[0],
|
||||
}
|
||||
);
|
||||
|
||||
@ -287,12 +292,10 @@ ${items
|
||||
`;
|
||||
|
||||
// Render all present sections for the given changelog
|
||||
return `# ${changelog.version} (${changelog.releaseDate})
|
||||
|
||||
${section('Breaking changes', changelog.breaking)}
|
||||
return `${section('Features and enhancements', changelog.features)}
|
||||
${section('Bug fixes', changelog.bugfixes)}
|
||||
${section('Breaking changes', changelog.breaking)}
|
||||
${section('Plugin development fixes & changes', changelog.plugins)}
|
||||
${section('Features and enhancements', changelog.features)}
|
||||
`;
|
||||
};
|
||||
|
||||
@ -314,4 +317,3 @@ if (process.env.INPUT_OUTPUT_FILE) {
|
||||
LOG(`Output to ${process.env.INPUT_OUTPUT_FILE}`);
|
||||
writeFileSync(process.env.INPUT_OUTPUT_FILE, md);
|
||||
}
|
||||
|
||||
|
85
.github/workflows/changelog.yml
vendored
85
.github/workflows/changelog.yml
vendored
@ -4,10 +4,23 @@ on:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
description: 'Target release version (git tag)'
|
||||
prev_version:
|
||||
description: 'Target release version (semver, git tag, branch or commit)'
|
||||
target:
|
||||
required: true
|
||||
description: 'Previous release version (git tag)'
|
||||
type: string
|
||||
description: 'The base branch that these changes are being merged into'
|
||||
dry_run:
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
latest:
|
||||
required: false
|
||||
default: false
|
||||
type: bool
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
@ -23,21 +36,67 @@ jobs:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
with:
|
||||
sparse-checkout: .github/workflows
|
||||
sparse-checkout: |
|
||||
.github/workflows
|
||||
CHANGELOG.md
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- name: "Configure git user"
|
||||
run: |
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local --add --bool push.autoSetupRemote true
|
||||
- name: "Create branch"
|
||||
run: git checkout -b "release/${{ github.run_id }}/${{ inputs.version }}"
|
||||
- name: "Generate changelog"
|
||||
id: changelog
|
||||
uses: ./.github/workflows/actions/changelog
|
||||
with:
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
version: ${{ inputs.version }}
|
||||
prev_version: ${{ inputs.prev_version }}
|
||||
output_file: _changelog.md
|
||||
- name: "Draft Github Release"
|
||||
github_token: ${{ steps.generate_token.outputs.token }}
|
||||
target: v${{ inputs.version }}
|
||||
output_file: changelog_items.md
|
||||
- name: "Patch CHANGELOG.md"
|
||||
run: |
|
||||
# Prepare CHANGELOG.md content with version delimiters
|
||||
(
|
||||
echo
|
||||
echo "# ${{ inputs.version}} ($(date '+%F'))"
|
||||
echo
|
||||
cat changelog_items.md
|
||||
) > CHANGELOG.part
|
||||
|
||||
# Check if a version exists in the changelog
|
||||
if grep -q "<!-- ${{ inputs.version}} START" CHANGELOG.md ; then
|
||||
# Replace the content between START and END delimiters
|
||||
echo "Version ${{ inputs.version }} is found in the CHANGELOG.md, patching contents..."
|
||||
sed -i -e '/${{ inputs.version }} START/,/${{ inputs.version }} END/{//!d;}' \
|
||||
-e '/${{ inputs.version }} START/r CHANGELOG.part' CHANGELOG.md
|
||||
else
|
||||
# Prepend changelog part to the main changelog file
|
||||
echo "Version ${{ inputs.version }} not found in the CHANGELOG.md"
|
||||
(
|
||||
echo "<!-- ${{ inputs.version }} START -->"
|
||||
cat CHANGELOG.part
|
||||
echo "<!-- ${{ inputs.version }} END -->"
|
||||
cat CHANGELOG.md
|
||||
) > CHANGELOG.tmp
|
||||
mv CHANGELOG.tmp CHANGELOG.md
|
||||
fi
|
||||
|
||||
git diff CHANGELOG.md
|
||||
- name: "Commit changelog changes"
|
||||
run: git commit --allow-empty -m "Update changelog placeholder" CHANGELOG.md
|
||||
- name: "git push"
|
||||
if: ${{ inputs.dry_run }} != true
|
||||
run: git push
|
||||
- name: "Create changelog PR"
|
||||
if: "${{ inputs.backport == '' }}"
|
||||
run: >
|
||||
gh pr create \
|
||||
$( [ "x${{ inputs.latest }}" == "xtrue" ] && printf %s '-l "release/latest"') \
|
||||
--dry-run=${{ inputs.dry_run }} \
|
||||
-B "${{ inputs.target }}" \
|
||||
--title "Release: ${{ inputs.version }}" \
|
||||
--body "Changelog changes for release ${{ inputs.version }}"
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
run: |
|
||||
cat _changelog.md
|
||||
# skip for now
|
||||
# gh release create --draft ${{ inputs.version }} --notes-file _changelog.md
|
||||
|
71
.github/workflows/release-pr.yml
vendored
71
.github/workflows/release-pr.yml
vendored
@ -30,7 +30,7 @@ on:
|
||||
type: bool
|
||||
|
||||
permissions:
|
||||
content: write
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
@ -39,44 +39,103 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'grafana/grafana'
|
||||
steps:
|
||||
|
||||
- name: Generate bot token
|
||||
id: generate_token
|
||||
uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92
|
||||
with:
|
||||
app_id: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_ID }}
|
||||
private_key: ${{ secrets.GRAFANA_DELIVERY_BOT_APP_PEM }}
|
||||
|
||||
- name: Checkout Grafana
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Configure git user
|
||||
run: |
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local --add --bool push.autoSetupRemote true
|
||||
|
||||
- name: Create branch
|
||||
run: git checkout -b "release/${{ github.run_id }}/${{ inputs.version }}"
|
||||
|
||||
- name: Generate changelog
|
||||
run: git commit --allow-empty -m "Update changelog placeholder"
|
||||
id: changelog
|
||||
uses: ./.github/workflows/actions/changelog
|
||||
with:
|
||||
github_token: ${{ steps.generate_token.outputs.token }}
|
||||
target: v${{ inputs.version }}
|
||||
output_file: changelog_items.md
|
||||
|
||||
- name: Patch CHANGELOG.md
|
||||
run: |
|
||||
# Prepare CHANGELOG.md content with version delimiters
|
||||
(
|
||||
echo
|
||||
echo "# ${{ inputs.version}} ($(date '+%F'))"
|
||||
echo
|
||||
cat changelog_items.md
|
||||
) > CHANGELOG.part
|
||||
|
||||
# Check if a version exists in the changelog
|
||||
if grep -q "<!-- ${{ inputs.version}} START" CHANGELOG.md ; then
|
||||
# Replace the content between START and END delimiters
|
||||
echo "Version ${{ inputs.version }} is found in the CHANGELOG.md, patching contents..."
|
||||
sed -i -e '/${{ inputs.version }} START/,/${{ inputs.version }} END/{//!d;}' \
|
||||
-e '/${{ inputs.version }} START/r CHANGELOG.part' CHANGELOG.md
|
||||
else
|
||||
# Prepend changelog part to the main changelog file
|
||||
echo "Version ${{ inputs.version }} not found in the CHANGELOG.md"
|
||||
(
|
||||
echo "<!-- ${{ inputs.version }} START -->"
|
||||
cat CHANGELOG.part
|
||||
echo "<!-- ${{ inputs.version }} END -->"
|
||||
cat CHANGELOG.md
|
||||
) > CHANGELOG.tmp
|
||||
mv CHANGELOG.tmp CHANGELOG.md
|
||||
fi
|
||||
|
||||
rm -f CHANGELOG.part changelog_items.md
|
||||
|
||||
git diff CHANGELOG.md
|
||||
|
||||
- name: Commit CHANGELOG.md changes
|
||||
run: git commit --allow-empty -m "Update changelog placeholder" CHANGELOG.md
|
||||
|
||||
- name: Update package.json versions
|
||||
uses: ./pkg/build/actions/bump-version
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
- name: add package.json changes
|
||||
|
||||
- name: Add package.json changes
|
||||
run: |
|
||||
git add .
|
||||
git commit -m "Update version to ${{ inputs.version }}"
|
||||
- name: git push
|
||||
|
||||
- name: Git push
|
||||
if: ${{ inputs.dry_run }} != true
|
||||
run: git push
|
||||
|
||||
- name: Create PR without backports
|
||||
if: "${{ inputs.backport == '' }}"
|
||||
run: >
|
||||
gh pr create \
|
||||
$( (( ${{ inputs.latest }} == "true" )) && printf %s '-l "release/latest"') \
|
||||
$( [ "x${{ inputs.latest }}" == "xtrue" ] && printf %s '-l "release/latest"') \
|
||||
--dry-run=${{ inputs.dry_run }} \
|
||||
-B "${{ inputs.target }}" \
|
||||
--title "Release: ${{ inputs.version }}" \
|
||||
--body "These code changes must be merged after a release is complete"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create PR with backports
|
||||
if: "${{ inputs.backport != '' }}"
|
||||
run: >
|
||||
gh pr create \
|
||||
$( (( ${{ inputs.latest }} == "true" )) && printf %s '-l "release/latest"') \
|
||||
$( [ "x${{ inputs.latest }}" == "xtrue" ] && printf %s '-l "release/latest"') \
|
||||
-l "backport ${{ inputs.backport }}" \
|
||||
-l "product-approved" \
|
||||
--dry-run=${{ inputs.dry_run }} \
|
||||
|
Loading…
Reference in New Issue
Block a user