Skip to content

Commit 0f870a4

Browse files
dmytrokirpaclaude
andauthored
chore: add release pipeline for react-headless-components-preview (#36063)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 06715ba commit 0f870a4

7 files changed

Lines changed: 162 additions & 6 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
pr: none
2+
trigger: none
3+
4+
# Customize build number to include package prefix
5+
# Example: headless_20201022.1
6+
name: 'headless_$(Date:yyyyMMdd)$(Rev:.r)'
7+
8+
parameters:
9+
- name: dryRun
10+
displayName: Dry Run Mode
11+
type: boolean
12+
default: false
13+
14+
variables:
15+
- group: 'Github and NPM secrets'
16+
- template: .devops/templates/variables.yml
17+
parameters:
18+
skipComponentGovernanceDetection: false
19+
- name: tags
20+
value: production,externalfacing
21+
22+
resources:
23+
repositories:
24+
- repository: 1esPipelines
25+
type: git
26+
name: 1ESPipelineTemplates/1ESPipelineTemplates
27+
ref: refs/tags/release
28+
29+
extends:
30+
template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
31+
parameters:
32+
pool:
33+
name: Azure-Pipelines-1ESPT-ExDShared
34+
image: windows-latest
35+
os: windows # We need windows because compliance task only run on windows.
36+
stages:
37+
- stage: main
38+
jobs:
39+
- job: Release
40+
pool:
41+
name: '1ES-Host-Ubuntu'
42+
image: '1ES-PT-Ubuntu-20.04'
43+
os: linux
44+
timeoutInMinutes: 90
45+
workspace:
46+
clean: all
47+
templateContext:
48+
outputParentDirectory: $(System.DefaultWorkingDirectory)
49+
outputs:
50+
- output: pipelineArtifact
51+
targetPath: $(System.DefaultWorkingDirectory)
52+
artifactName: output
53+
steps:
54+
- template: .devops/templates/tools.yml@self
55+
parameters:
56+
dryRun: ${{ parameters.dryRun }}
57+
58+
- script: |
59+
git config user.name "Fluent UI Build"
60+
git config user.email "fluentui-internal@service.microsoft.com"
61+
git remote set-url origin https://$(githubUser):$(githubPAT)@github.com/microsoft/fluentui.git
62+
displayName: Authenticate git for pushes
63+
64+
- task: Bash@3
65+
inputs:
66+
filePath: yarn-ci.sh
67+
displayName: yarn
68+
69+
- script: |
70+
echo "Following packages will be published (if they contain changes):"
71+
yarn nx show projects -p 'tag:react-headless,!tag:npm:private' --exclude 'apps/**'
72+
displayName: Show packages
73+
74+
- script: |
75+
FLUENT_PROD_BUILD=true yarn nx run-many -t build -p 'tag:react-headless,!tag:npm:private,!tag:type:stories' --exclude 'apps/**' --nxBail
76+
displayName: build
77+
78+
- script: |
79+
FLUENT_PROD_BUILD=true yarn nx run-many -t test -p 'tag:react-headless,!tag:npm:private,!tag:type:stories' --exclude 'apps/**' --nxBail
80+
displayName: test
81+
82+
- script: |
83+
FLUENT_PROD_BUILD=true yarn nx run-many -t lint -p 'tag:react-headless,!tag:npm:private,!tag:type:stories' --exclude 'apps/**' --nxBail
84+
displayName: lint
85+
86+
- script: |
87+
yarn publish:beachball -n $(npmToken) --config scripts/beachball/src/release-headless.config.js --message 'release: applying package updates - react-headless'
88+
git reset --hard origin/master
89+
env:
90+
GITHUB_PAT: $(githubPAT)
91+
displayName: Publish changes and bump versions
92+
condition: not(${{ parameters.dryRun }})
93+
94+
- template: .devops/templates/cleanup.yml@self
95+
parameters:
96+
checkForModifiedFiles: false
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "chore: update project nx tag",
4+
"packageName": "@fluentui/react-headless-components-preview",
5+
"email": "dmytrokirpa@microsoft.com",
6+
"dependentChangeType": "patch"
7+
}

packages/react-components/react-headless-components-preview/library/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
44
"projectType": "library",
55
"sourceRoot": "packages/react-components/react-headless-components-preview/library/src",
6-
"tags": ["platform:web", "vNext"],
6+
"tags": ["vNext", "platform:web", "react-headless"],
77
"implicitDependencies": [],
88
"targets": {
99
"generate-api": {

packages/react-components/react-headless-components-preview/stories/project.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
44
"projectType": "library",
55
"sourceRoot": "packages/react-components/react-headless-components-preview/stories/src",
6-
"tags": ["vNext", "platform:web", "type:stories"],
6+
"tags": ["vNext", "platform:web", "type:stories", "react-headless"],
77
"implicitDependencies": []
88
}

scripts/beachball/src/config.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import headlessConfig from './release-headless.config';
12
import toolsConfig from './release-tools.config';
23
import v8Config from './release-v8.config';
34
import vNextConfig from './release-vNext.config';
@@ -99,6 +100,9 @@ describe(`beachball configs`, () => {
99100

100101
// Ensure that vNext config does not include "tools" packages
101102
expect(vNextConfig.scope.some(scope => toolsConfig.scope.includes(scope))).toBe(false);
103+
104+
// Ensure that vNext config does not include "react-headless" packages
105+
expect(vNextConfig.scope.some(scope => headlessConfig.scope.includes(scope))).toBe(false);
102106
});
103107

104108
it(`should generate web-components release config`, () => {
@@ -113,6 +117,22 @@ describe(`beachball configs`, () => {
113117
expect(webComponentsConfig.changelog).toEqual(sharedConfig.changelog);
114118
});
115119

120+
it(`should generate react-headless release config`, () => {
121+
expect(headlessConfig.scope).toEqual(
122+
expect.arrayContaining(['packages/react-components/react-headless-components-preview/library']),
123+
);
124+
125+
// Ensure only headless packages are included, not broader vNext or tools packages
126+
const nonHeadlessScopes = [
127+
'packages/react-components/react-components',
128+
'packages/react-components/react-button',
129+
'packages/react',
130+
];
131+
expect(headlessConfig.scope.some(scope => nonHeadlessScopes.includes(scope))).toBe(false);
132+
133+
expect(headlessConfig.changelog).toEqual(sharedConfig.changelog);
134+
});
135+
116136
it(`should generate tools release config`, () => {
117137
expect(toolsConfig.scope).toEqual(
118138
expect.arrayContaining([
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require('./register').register();
2+
3+
const { config: sharedConfig } = require('./shared.config');
4+
const { getConfig } = require('./utils');
5+
6+
const { scope } = getConfig({ version: 'headless' });
7+
8+
/**
9+
* @type {typeof sharedConfig}
10+
*/
11+
const config = {
12+
...sharedConfig,
13+
scope,
14+
};
15+
16+
module.exports = config;

scripts/beachball/src/utils.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getAllPackageInfo, isConvergedPackage } from '@fluentui/scripts-monorep
1010
export function getConfig({ version }: { version: 'web-components' }): { scope: string[] };
1111
export function getConfig({ version }: { version: 'v8' }): { scope: string[] };
1212
export function getConfig({ version }: { version: 'tools' }): { scope: string[] };
13+
export function getConfig({ version }: { version: 'headless' }): { scope: string[] };
1314
export function getConfig({ version }: { version: 'vNext' }): {
1415
scope: string[];
1516
groupConfig: {
@@ -18,8 +19,8 @@ export function getConfig({ version }: { version: 'vNext' }): {
1819
include: string[];
1920
};
2021
};
21-
export function getConfig({ version }: { version: 'v8' | 'vNext' | 'web-components' | 'tools' }) {
22-
const { vNextPaths, webComponentsPaths, toolsPaths, v8Paths } = getPackagePaths();
22+
export function getConfig({ version }: { version: 'v8' | 'vNext' | 'web-components' | 'tools' | 'headless' }) {
23+
const { vNextPaths, webComponentsPaths, toolsPaths, v8Paths, headlessPaths } = getPackagePaths();
2324

2425
if (version === 'vNext') {
2526
return {
@@ -48,6 +49,12 @@ export function getConfig({ version }: { version: 'v8' | 'vNext' | 'web-componen
4849
};
4950
}
5051

52+
if (version === 'headless') {
53+
return {
54+
scope: [...headlessPaths],
55+
};
56+
}
57+
5158
throw new Error('Unsupported version scopes acquisition');
5259
}
5360

@@ -66,18 +73,25 @@ const isToolsPackage: typeof isConvergedPackage = metadata => {
6673

6774
return hasToolsTag && !isPrivate && !isV8Package(metadata);
6875
};
76+
const isHeadlessPackage: typeof isConvergedPackage = metadata => {
77+
const hasHeadlessTag = Boolean(metadata.project.tags?.includes('react-headless'));
78+
const isPrivate = Boolean(metadata.packageJson.private);
79+
80+
return hasHeadlessTag && !isPrivate;
81+
};
6982

7083
function getPackagePaths() {
7184
const allProjects = getAllPackageInfo();
7285
const vNextPaths: string[] = [];
7386
const webComponentsPaths: string[] = [];
7487
const v8Paths: string[] = [];
7588
const toolsPaths: string[] = [];
89+
const headlessPaths: string[] = [];
7690

7791
for (const project of Object.values(allProjects)) {
7892
const isPrivate = Boolean(project.packageJson.private);
7993
const metadata = { project: project.projectConfig, packageJson: project.packageJson };
80-
if (isConvergedPackage(metadata) && !isToolsPackage(metadata) && !isPrivate) {
94+
if (isConvergedPackage(metadata) && !isToolsPackage(metadata) && !isHeadlessPackage(metadata) && !isPrivate) {
8195
vNextPaths.push(project.packagePath);
8296
}
8397
if (isWebComponentPackage(metadata)) {
@@ -89,7 +103,10 @@ function getPackagePaths() {
89103
if (isV8Package(metadata)) {
90104
v8Paths.push(project.packagePath);
91105
}
106+
if (isHeadlessPackage(metadata)) {
107+
headlessPaths.push(project.packagePath);
108+
}
92109
}
93110

94-
return { vNextPaths, webComponentsPaths, toolsPaths, v8Paths };
111+
return { vNextPaths, webComponentsPaths, toolsPaths, v8Paths, headlessPaths };
95112
}

0 commit comments

Comments
 (0)