Skip to content

Commit

Permalink
build: introduce trunk based development workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Oct 28, 2024
1 parent 5e27ba2 commit 99e3ad8
Show file tree
Hide file tree
Showing 8 changed files with 525 additions and 1 deletion.
62 changes: 62 additions & 0 deletions .github/workflows/maintenance-changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: cherry-pick changelog from release branch into default branch

on:
push:
tags: ['*.*']

permissions:
actions: write
issues: write

jobs:
cherry_pick:
runs-on: ubuntu-latest
outputs:
failed_release_version: ${{ steps.cherry_pick_error.outputs.failed_release_version }}
steps:
- name: Get token
id: get_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.MAINTENANCE_APP_ID }}
private_key: ${{ secrets.MAINTENANCE_APP_PEM }}
- uses: actions/checkout@v4
with:
token: ${{ steps.get_token.outputs.app_token }}
fetch-depth: 0
- name: Get tag name
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Get commit for tag
run: echo "TAG_COMMIT=$(git rev-list -n 1 ${{ env.RELEASE_VERSION }})" >> $GITHUB_ENV
- name: Cherry-pick CHANGELOG.md into ${{ github.event.repository.default_branch }}
run: |
git config user.email "[email protected]"
git config user.name "github-actions"
git checkout ${{ github.event.repository.default_branch }}
git show ${{ env.TAG_COMMIT }} -- CHANGELOG.md | git apply -
git commit -a -m "chore: update changelog"
git push
- name: Handling error
if: ${{ failure() }}
id: cherry_pick_error
run: echo "failed_release_version=$(echo ${{ env.RELEASE_VERSION }})" >> $GITHUB_OUTPUT

update_maintenance_issue:
runs-on: ubuntu-latest
needs: cherry_pick
if: always() && needs.cherry_pick.result == 'failure'
steps:
- run: echo ${{ needs.cherry_pick.outputs.failed_release_version }}
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
if: needs.cherry_pick.outputs.failed_release_version
with:
node-version-file: .nvmrc
- run: yarn install --frozen-lockfile --non-interactive
if: needs.cherry_pick.outputs.failed_release_version
- name: Update maintenance issue
if: needs.cherry_pick.outputs.failed_release_version
run: node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/update-maintenance-issue.mts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FAILED_RELEASE: ${{ needs.cherry_pick.outputs.failed_release_version }}
85 changes: 85 additions & 0 deletions .github/workflows/maintenance-cherry-pick.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: cherry-pick into target branches

on:
pull_request:
types: [closed]

permissions:
actions: write
issues: write

jobs:
# Check if labels exist before executing the next job.
# We cannot use `if` because the matrix is evaluated before the `if` statement.
check_labels:
runs-on: ubuntu-latest
if: ${{ join(github.event.pull_request.labels) != '' }}
steps:
- run: echo Labels are not empty, continuing

cherry_pick:
needs: [check_labels]
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true &&
github.event.pull_request.user.login != 'renovate[bot]'
outputs:
failed_branches: ${{ steps.update_failed_branches.outputs.failed_branches }}
strategy:
matrix:
label: ${{ github.event.pull_request.labels.*.name }}

steps:
- name: Get token
id: get_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.MAINTENANCE_APP_ID }}
private_key: ${{ secrets.MAINTENANCE_APP_PEM }}
- name: Get branch name from label
id: branch_name
run: |
echo "branch=$(echo ${{ matrix.label }} | sed -n 's/target: \([0-9]*.x\).*/\1/p')" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4
if: steps.branch_name.outputs.branch
with:
token: ${{ steps.get_token.outputs.app_token }}
fetch-depth: 0

- name: Cherry-pick changes into ${{ steps.branch_name.outputs.branch }}
if: steps.branch_name.outputs.branch
run: |
git checkout ${{ steps.branch_name.outputs.branch }}
git -c user.name="github-actions" -c user.email="[email protected]" cherry-pick ${{ github.sha }}
git push
- name: Update failed branches
if: ${{ failure() }}
id: update_failed_branches
run: |
echo "failed_branches=$(echo ${{ steps.branch_name.outputs.branch }} ${{ steps.update_failed_branches.outputs.failed_branches}})" >> $GITHUB_OUTPUT
update_maintenance_issue:
runs-on: ubuntu-latest
needs: cherry_pick
if: always() && needs.cherry_pick.result == 'failure' &&
github.event.pull_request.user.login != 'renovate[bot]'

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
if: needs.cherry_pick.outputs.failed_branches
with:
node-version-file: .nvmrc

- run: yarn install --frozen-lockfile --non-interactive
if: needs.cherry_pick.outputs.failed_branches

- name: Update maintenance issue
if: needs.cherry_pick.outputs.failed_branches
run: node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/update-maintenance-issue.mts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.number }}
FAILED_BRANCHES: ${{ needs.cherry_pick.outputs.failed_branches }}
28 changes: 28 additions & 0 deletions .github/workflows/maintenance-tagging.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Add or remove maintenance labels

on:
pull_request:
types: [opened, edited, labeled]
branches: [main] # target branch

env:
TARGET_RELEASE: 1.x

permissions:
pull-requests: write

jobs:
add_label:
runs-on: ubuntu-latest
if: github.event.pull_request.user.login != 'renovate[bot]'
steps:
- name: Add target label
if: "${{ !contains(github.event.pull_request.body, 'BREAKING CHANGE:') && !contains(github.event.pull_request.labels.*.name, 'target: major') }}"
uses: actions-ecosystem/action-add-labels@v1
with:
labels: 'target: ${{ env.TARGET_RELEASE }}'
- name: Remove target label
if: "${{ contains(github.event.pull_request.body, 'BREAKING CHANGE:') || contains(github.event.pull_request.labels.*.name, 'target: major') }}"
uses: actions-ecosystem/action-remove-labels@v1
with:
labels: 'target: ${{ env.TARGET_RELEASE }}'
2 changes: 1 addition & 1 deletion .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Release Please
on:
push:
branches:
- main
- '*.x'

# Documentation:
# https://github.com/googleapis/release-please
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
"lit-analyzer": "2.0.3",
"madge": "8.0.0",
"npm-run-all2": "7.0.1",
"octokit": "4.0.2",
"playwright": "1.47.2",
"postcss": "8.4.47",
"prettier": "3.3.3",
Expand Down
1 change: 1 addition & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"nvm": {
"enabled": false
},
"baseBranches": ["main", "1.x"],
"lockFileMaintenance": {
"schedule": ["before 7am on monday"],
"enabled": true
Expand Down
86 changes: 86 additions & 0 deletions scripts/update-maintenance-issue.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Octokit } from 'octokit';
import { fileURLToPath } from 'url';

const githubToken = process.env['GITHUB_TOKEN'];
const pullRequestNumber = parseInt(process.env['PR_NUMBER']!, 10);
const failedBranches = process.env['FAILED_BRANCHES']?.split(' ').join(', ');
const failedReleaseVersion = process.env['FAILED_RELEASE'];

const repoConfig = {
owner: 'sbb-design-systems',
repo: 'lyne-components',
};

const issuePath = {
...repoConfig,
issue_number: 3176,
};

const prPath = {
...repoConfig,
pull_number: pullRequestNumber,
};

class MaintenanceIssueUpdater {
constructor(
private _octokit: Octokit,
private _now: Date,
) {}

async run() {
if (!failedBranches && !failedReleaseVersion) {
throw new Error(
`Unable to update maintenance issue.
Please either specify FAILED_BRANCHES or FAILED_RELEASE`,
);
}

const issue = await this._octokit.rest.issues.get(issuePath);

if (!issue.data.body) {
throw new Error('Could not load issue body');
}

const hint = '**Cherry-pick failed for the following pull requests / releases**';
const dateInfo = `${this._now.toISOString()}`;
let openTasks = this._extractOpenTasks(issue.data.body);
let newTask;

if (failedBranches) {
const pr = await this._octokit.rest.pulls.get(prPath);
if (!pr.data.title || !pr.data.html_url) {
throw new Error('Could not load pull request');
}

newTask = `- [ ] PR [${pr.data.title}](${pr.data.html_url}) could not be cherry-picked into branch ${failedBranches})`;
} else {
newTask = `- [ ] CHANGELOG.md could not be cherry-picked for release ${failedReleaseVersion}`;
}

openTasks = this._addNewTask(openTasks, newTask);

return this._octokit.rest.issues.update({
...issuePath,
body: `${hint}\n${openTasks.join('\n')}\n\n${dateInfo}`,
});
}

private _extractOpenTasks(issueBody: string = ''): string[] {
return issueBody.split('\n').filter((line) => line.startsWith('- [ ]'));
}

private _addNewTask(tasks: string[], newTask: string): string[] {
const newTasks = [newTask, ...tasks];
return [...new Set(newTasks)];
}
}

if (process.argv[1] === fileURLToPath(import.meta.url)) {
const maintenanceIssueUpdater = new MaintenanceIssueUpdater(
new Octokit({
auth: githubToken,
}),
new Date(),
);
maintenanceIssueUpdater.run();
}
Loading

0 comments on commit 99e3ad8

Please sign in to comment.