-
Notifications
You must be signed in to change notification settings - Fork 34
[CI] Adding release notes for non-rc versions & PR validations workflows #289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
3e26ccb
91aa535
355728a
ba88c03
5ed1f83
9640e9c
cbe71fc
6264877
3413976
8ec1302
72ae161
e51bd28
c5d7b50
6cb4f4b
79daf5b
0aa31b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| name: PR Validation | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, edited, reopened, synchronize] | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add conmcurrency to avoid race conditions |
||
| jobs: | ||
| validate-and-label: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Validate PR title and assign label | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: "${{ secrets.GITHUB_TOKEN }}" | ||
| script: | | ||
| const title = context.payload.pull_request.title; | ||
| const prNumber = context.payload.pull_request.number; | ||
|
|
||
| const allowedScopes = ['feature', 'fix', 'docs', 'improvement', 'revert', 'breaking', 'ci']; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The allowed scopes (feature, fix, docs, improvement, revert, breaking, ci) don't align with cliff.toml's commit parsers (feat, fix, perf, refactor, docs, chore, revert, breaking). feature passes validation but won't match [feat] in cliff |
||
|
|
||
| const scopeToLabel = { | ||
| feature: 'feature', | ||
| ci: 'ci', | ||
| fix: 'bug', | ||
| docs: 'documentation', | ||
| improvement: 'improvement', | ||
| revert: 'revert', | ||
| breaking: 'breaking-change', | ||
| }; | ||
|
|
||
| const match = title.match(/^\[([^\]]+)\]\s+\S+/); | ||
|
|
||
| if (!match) { | ||
| core.setFailed( | ||
| `PR title must follow the format: [scope] description\n` + | ||
| `Allowed scopes (case-insensitive): [Feature], [Fix], [Docs], [Improvement], [Revert], [Breaking], [CI]\n` + | ||
| `Example: [Feature] Add SeaweedFS bucket auto-creation` | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const scope = match[1].toLowerCase(); | ||
|
|
||
| if (!allowedScopes.includes(scope)) { | ||
| core.setFailed( | ||
| `Invalid scope "[${match[1]}]".\n` + | ||
| `Allowed scopes (case-insensitive): [Feature], [Fix], [Docs], [Improvement], [Revert], [Breaking], [CI]\n` + | ||
| `Example: [Fix] Resolve crash on startup` | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const labelName = scopeToLabel[scope]; | ||
|
|
||
| // Remove any stale scope labels from a previous title edit | ||
| const allScopeLabels = Object.values(scopeToLabel); | ||
| const currentLabels = context.payload.pull_request.labels.map(l => l.name); | ||
|
|
||
| for (const stale of currentLabels) { | ||
| if (allScopeLabels.includes(stale) && stale !== labelName) { | ||
| await github.rest.issues.removeLabel({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| name: stale, | ||
| }); | ||
| core.info(`Removed stale label: ${stale}`); | ||
| } | ||
| } | ||
|
|
||
| // Apply the correct label if not already present | ||
| if (!currentLabels.includes(labelName)) { | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| labels: [labelName], | ||
| }); | ||
| } | ||
|
|
||
| core.info(`PR title valid — scope: [${scope}] → label: ${labelName}`); | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -36,6 +36,21 @@ jobs: | |||||
| git config user.name "$GITHUB_ACTOR" | ||||||
| git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||||||
|
|
||||||
| - name: Extract Chart Version and check RC | ||||||
| id: version_check | ||||||
| run: | | ||||||
| CHART_VERSION=$(grep '^version:' charts/mlrun-ce/Chart.yaml | awk '{print $2}') | ||||||
| if [[ -z "$CHART_VERSION" ]]; then | ||||||
| echo "Error: Failed to extract version from Chart.yaml" >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| echo "version=$CHART_VERSION" >> $GITHUB_OUTPUT | ||||||
| if [[ "$CHART_VERSION" =~ -rc ]]; then | ||||||
| echo "is_rc=true" >> $GITHUB_OUTPUT | ||||||
| else | ||||||
| echo "is_rc=false" >> $GITHUB_OUTPUT | ||||||
| fi | ||||||
|
|
||||||
| - name: Add Helm Repos | ||||||
| run: | | ||||||
| helm repo add stable https://charts.helm.sh/stable | ||||||
|
|
@@ -52,18 +67,57 @@ jobs: | |||||
| env: | ||||||
| CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||||
|
|
||||||
| - name: Extract Chart Version from Chart.yaml | ||||||
| id: extract_version | ||||||
| - name: Find first RC tag for this version | ||||||
| if: steps.version_check.outputs.is_rc == 'false' | ||||||
| id: first_rc | ||||||
| run: | | ||||||
| CHART_VERSION=$(grep '^version:' charts/mlrun-ce/Chart.yaml | awk '{print $2}') | ||||||
| if [[ -z "$CHART_VERSION" ]]; then | ||||||
| echo "Error: Failed to extract version from Chart.yaml" >&2 | ||||||
| exit 1 | ||||||
| VERSION="${{ steps.version_check.outputs.version }}" | ||||||
|
|
||||||
| FIRST_RC=$(git tag --sort=version:refname \ | ||||||
| | grep "^mlrun-ce-${VERSION}-rc\." \ | ||||||
| | head -1) | ||||||
|
|
||||||
| if [[ -n "$FIRST_RC" ]]; then | ||||||
| echo "range=${FIRST_RC}^..HEAD" >> $GITHUB_OUTPUT | ||||||
| echo "Range start: first RC tag ${FIRST_RC}" | ||||||
| else | ||||||
| # Hotfix with no RC — use previous stable tag so notes cover only this version | ||||||
| PREV_STABLE=$(git tag --sort=version:refname \ | ||||||
| | grep "^mlrun-ce-[0-9]" \ | ||||||
| | grep -v "\-rc\." \ | ||||||
| | grep -v "^mlrun-ce-${VERSION}$" \ | ||||||
| | tail -1) | ||||||
| if [[ -n "$PREV_STABLE" ]]; then | ||||||
| echo "range=${PREV_STABLE}..HEAD" >> $GITHUB_OUTPUT | ||||||
| echo "Range start: previous stable tag ${PREV_STABLE}" | ||||||
| else | ||||||
| echo "range=HEAD" >> $GITHUB_OUTPUT | ||||||
| echo "Range start: none (first ever release)" | ||||||
| fi | ||||||
| fi | ||||||
| echo "version=$CHART_VERSION" >> $GITHUB_OUTPUT | ||||||
|
|
||||||
| - name: Generate release notes with git-cliff | ||||||
| if: steps.version_check.outputs.is_rc == 'false' | ||||||
| uses: orhun/git-cliff-action@v4 | ||||||
| with: | ||||||
| config: cliff.toml | ||||||
| args: >- | ||||||
| ${{ steps.first_rc.outputs.range }} | ||||||
| --tag mlrun-ce-${{ steps.version_check.outputs.version }} | ||||||
| --ignore-tags "mlrun-ce-${{ steps.version_check.outputs.version }}-rc.*" | ||||||
| env: | ||||||
| OUTPUT: RELEASE_NOTES.md | ||||||
|
|
||||||
| - name: Update GitHub Release with release notes | ||||||
| if: steps.version_check.outputs.is_rc == 'false' | ||||||
| env: | ||||||
| CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just use the same ENV the job has been using already - link if i change this should I change the old one also? |
||||||
| run: | | ||||||
| gh release edit "mlrun-ce-${{ steps.version_check.outputs.version }}" \ | ||||||
|
yaelgen marked this conversation as resolved.
|
||||||
| --notes-file RELEASE_NOTES.md | ||||||
|
|
||||||
| outputs: | ||||||
| version: ${{ steps.extract_version.outputs.version }} | ||||||
| version: ${{ steps.version_check.outputs.version }} | ||||||
|
|
||||||
| deploy_ce_onprem: | ||||||
| needs: release | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| [changelog] | ||
| header = "" | ||
| body = """ | ||
| {% for group, commits in commits | sort(attribute="group") | group_by(attribute="group") %}\ | ||
| ### {{ group | striptags | trim | upper_first }} | ||
| {% for commit in commits %}\ | ||
| - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ | ||
| {% if commit.breaking %}[**breaking**] {% endif %}\ | ||
| {{ commit.message | split(pat="\n") | first | upper_first }} \ | ||
| ([{{ commit.id | truncate(length=7, end="") }}](https://github.com/mlrun/ce/commit/{{ commit.id }}))\ | ||
| \n \ | ||
| {% endfor %} | ||
| {% endfor %}\n | ||
| """ | ||
| trim = true | ||
| footer = "" | ||
|
|
||
| [git] | ||
| conventional_commits = false | ||
| filter_unconventional = false | ||
| split_commits = false | ||
| commit_preprocessors = [] | ||
| commit_parsers = [ | ||
| # skip merge commits | ||
| { message = "(?i)^merge", skip = true }, | ||
|
|
||
| # new PR title format (enforced by pr-validation.yml): [scope] description | ||
| # allowed scopes: feature, fix, docs, improvement, revert, breaking, ci | ||
| { message = "(?i)^\\[feature\\]", group = "Features" }, | ||
| { message = "(?i)^\\[fix\\]", group = "Bug Fixes" }, | ||
| { message = "(?i)^\\[docs\\]", group = "Documentation" }, | ||
| { message = "(?i)^\\[improvement\\]", group = "Improvements" }, | ||
| { message = "(?i)^\\[revert\\]", group = "Reverts" }, | ||
| { message = "(?i)^\\[breaking\\]", group = "Breaking Changes" }, | ||
| { message = "(?i)^\\[ci\\]", group = "CI/CD" }, | ||
|
|
||
| # conventional commits format: feat: / fix: ... | ||
| { message = "(?i)^feat", group = "Features" }, | ||
| { message = "(?i)^fix", group = "Bug Fixes" }, | ||
| { message = "(?i)^refactor", group = "Improvements" }, | ||
| { message = "(?i)^docs?", group = "Documentation" }, | ||
| { message = "(?i)^chore\\(deps\\)", group = "Improvements" }, | ||
| { message = "(?i)^revert", group = "Reverts" }, | ||
|
|
||
| # historical [ComponentName] format — infer type from the verb in the message | ||
| { message = "(?i)^\\[[^\\]]+\\].*(fix|bug|broken|regression)", group = "Bug Fixes" }, | ||
| { message = "(?i)^\\[[^\\]]+\\].*(add|support|enable|upgrade|update|migrate|connect|expose|allow)", group = "Features" }, | ||
| { message = "(?i)^\\[[^\\]]+\\]", group = "Other" }, | ||
|
|
||
| # plain English fallback | ||
| { message = "(?i)^(fix|bug)", group = "Bug Fixes" }, | ||
| { message = "(?i)^(add|update|upgrade|support|enable|migrate|expose|allow)", group = "Features" }, | ||
| { message = "(?i)^(remove|disable|clean|deprecat)", group = "Other" }, | ||
|
|
||
| # catch-all — anything that didn't match above | ||
| { message = ".*", group = "Other" }, | ||
| ] | ||
| protect_breaking_commits = false | ||
| filter_commits = false | ||
| tag_pattern = "mlrun-ce-[0-9].*" | ||
| skip_tags = "" | ||
| ignore_tags = "" | ||
| topo_order = false | ||
| sort_commits = "newest" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can't change title on push - not sure why it is needed. dropped synchronize