Skip to content

Commit aa2aadc

Browse files
Add a dedicated page to view list of FFs that would be GA
1 parent c474ad2 commit aa2aadc

File tree

10 files changed

+539
-0
lines changed

10 files changed

+539
-0
lines changed

docusaurus.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ const config: Config = {
445445
label: 'Feature Requests',
446446
to: 'https://ideas.harness.io',
447447
},
448+
{
449+
label: 'Feature Flags GA List',
450+
to: '/feature-flags',
451+
},
448452
{
449453
label: 'Instructor-Led Training',
450454
to: '/university?ilt',
@@ -534,6 +538,16 @@ const config: Config = {
534538
},
535539
},
536540
],
541+
[
542+
path.resolve(__dirname, './plugins/docs-rss-plugin'),
543+
{
544+
id: 'feature-flags',
545+
path: 'feature-flags',
546+
routeBasePath: 'feature-flags',
547+
exclude: ['**/shared/**', '**/static/**', '**/content/**'],
548+
editUrl: 'https://github.com/harness/developer-hub/tree/main',
549+
},
550+
],
537551
// redirect plugin start
538552
[
539553
path.resolve(__dirname, './plugins/docsEnhanced-plugin'),
@@ -619,6 +633,7 @@ const config: Config = {
619633
path.join(__dirname, '/plugins/utmcookie-plugin'),
620634
path.join(__dirname, '/plugins/focusOnAnchor-plugin'),
621635
path.join(__dirname, '/plugins/feedback-plugin'),
636+
path.join(__dirname, '/plugins/feature-flags-rss-plugin'),
622637
],
623638
clientModules: [
624639
path.join(__dirname, '/client-modules/searchBar'),

feature-flags/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
sidebar_position: 0
3+
hide_table_of_contents: true
4+
hide_title: true
5+
title: Feature Flags
6+
slug: /
7+
date: 2024-11-13T10:00
8+
---
9+
10+
import FeatureFlagsLanding from '@site/src/components/FeatureFlagGA/FeatureFlagsLanding';
11+
import ffGAFeed from './static/ff-ga-feed.json';
12+
13+
<FeatureFlagsLanding staticFlags={ffGAFeed} />

feature-flags/static/ff-ga-feed.json

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
[
2+
{
3+
"flagKey": "CDS_ADD_DEPLOYMENT_FREEZE_BYPASS_AUDIT",
4+
"description": "Enables audit logging for deployment freeze bypass actions.",
5+
"gaStartDate": "2025-09-15",
6+
"module": "Continuous Delivery"
7+
},
8+
{
9+
"flagKey": "CDS_DEPLOYMENT_FREEZE_GRANULAR_RBAC",
10+
"description": "Provides granular role-based access control for deployment freeze operations based on environment type.",
11+
"gaStartDate": "2025-09-15",
12+
"module": "Continuous Delivery"
13+
},
14+
{
15+
"flagKey": "CDS_GITLAB_TRIGGER_TAG_EVENT",
16+
"description": "Enables GitLab tag event triggers for pipelines.",
17+
"gaStartDate": "2025-09-15",
18+
"module": "Continuous Delivery"
19+
},
20+
{
21+
"flagKey": "CDS_TF_POLICY_EVALUATION",
22+
"description": "Enables Terraform policy evaluation in Continuous Delivery workflows.",
23+
"gaStartDate": "2025-09-15",
24+
"module": "Continuous Delivery"
25+
},
26+
{
27+
"flagKey": "CDS_TEXTAREA_FOR_OVERRIDE_VARIABLES",
28+
"description": "Provides textarea input for override variables in deployment configurations.",
29+
"gaStartDate": "2025-09-15",
30+
"module": "Continuous Delivery"
31+
},
32+
{
33+
"flagKey": "CDS_TAS_LOGIN_OPTIMIZATION",
34+
"description": "Optimizes Tanzu Application Service (TAS) login performance and reliability by reducing the number of CLI initialisation calls.",
35+
"gaStartDate": "2025-09-15",
36+
"module": "Continuous Delivery"
37+
},
38+
{
39+
"flagKey": "CDS_SUPPORT_TF_CLOUD_PLAN_REFRESH_TYPE",
40+
"description": "Adds support for Terraform Cloud plan refresh type operations.",
41+
"gaStartDate": "2025-09-15",
42+
"module": "Continuous Delivery"
43+
},
44+
{
45+
"flagKey": "CDS_UI_ENABLE_DISALLOWED_USER_EMAILS_IN_APPROVAL_STEP",
46+
"description": "Enables configuration to block certain users from approving in Harness Approval steps based on emails.",
47+
"gaStartDate": "2025-09-15",
48+
"module": "Pipeline"
49+
},
50+
{
51+
"flagKey": "CDS_AZURE_OIDC_AUTHENTICATION",
52+
"description": "Enables OIDC authentication for Azure connectors.",
53+
"gaStartDate": "2025-09-15",
54+
"module": "Continuous Delivery"
55+
},
56+
{
57+
"flagKey": "CDS_GCP_LIST_PROJECTS_AUTH_FIX",
58+
"description": "Fixes authentication issues when listing Google Cloud Platform projects.",
59+
"gaStartDate": "2025-09-15",
60+
"module": "Continuous Delivery"
61+
},
62+
{
63+
"flagKey": "CDS_GCP_OIDC_CONNECTOR_CROSS_PROJECT_ACCESS",
64+
"description": "Enables cross-project access for Google Cloud Platform connectors.",
65+
"gaStartDate": "2025-09-15",
66+
"module": "Continuous Delivery"
67+
},
68+
{
69+
"flagKey": "CDS_OPTIONAL_VALUES_YAML",
70+
"description": "Enables optional values.yaml files in K8s & Helm deployments.",
71+
"gaStartDate": "2025-09-15",
72+
"module": "Continuous Delivery"
73+
},
74+
{
75+
"flagKey": "CDS_ENFORCE_GIT_EXPERIENCE",
76+
"description": "Enforces Git-based experience for CD entities such as service, environment, infrastructure and override configurations.",
77+
"gaStartDate": "2025-09-15",
78+
"module": "Continuous Delivery"
79+
},
80+
{
81+
"flagKey": "CDS_K8S_DETAILED_LOGS",
82+
"description": "Provides detailed logging for Kubernetes operations in CD.",
83+
"gaStartDate": "2025-09-15",
84+
"module": "Continuous Delivery"
85+
},
86+
{
87+
"flagKey": "CDS_INFRA_DEFINITION_VALIDATION",
88+
"description": "Enforces certain validation for infrastructure definitions in CD.",
89+
"gaStartDate": "2025-09-15",
90+
"module": "Continuous Delivery"
91+
},
92+
{
93+
"flagKey": "CDS_USE_SECONDARY_NODE_FOR_TIMESCALE_QUERIES",
94+
"description": "Internal optimisation to use secondary database nodes for TimescaleDB queries to improve performance.",
95+
"gaStartDate": "2025-09-15",
96+
"module": "Continuous Delivery"
97+
},
98+
{
99+
"flagKey": "CDS_ADD_EXPRESSION_RESOLUTION_FOR_OVERRIDES_V2_AT_SERVICE_STEP",
100+
"description": "Fixes a bug that resolves expressions in overrides at the service step.",
101+
"gaStartDate": "2025-09-15",
102+
"module": "Continuous Delivery"
103+
},
104+
{
105+
"flagKey": "CDS_OVERRIDES_GITX",
106+
"description": "Enables Git experience for service and infrastructure overrides management.",
107+
"gaStartDate": "2025-09-15",
108+
"module": "Continuous Delivery"
109+
},
110+
{
111+
"flagKey": "CDS_EVENT_BRIDGE_WEBHOOK",
112+
"description": "Enables Event Relay triggers for pipelines.",
113+
"gaStartDate": "2025-09-15",
114+
"module": "Continuous Delivery"
115+
},
116+
{
117+
"flagKey": "CDS_SERVICE_INFRA_FAILURE_STRATEGY",
118+
"description": "Implements failure strategies for service and infrastructure deployment steps.",
119+
"gaStartDate": "2025-09-15",
120+
"module": "Continuous Delivery"
121+
},
122+
{
123+
"flagKey": "CDS_OVERRIDES_V2_IDENTIFIER_SUPPORT",
124+
"description": "Adds identifier support for version 2 service and infrastructure overrides.",
125+
"gaStartDate": "2025-09-15",
126+
"module": "Continuous Delivery"
127+
}
128+
]

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"license": "MIT",
55
"private": true,
66
"scripts": {
7+
"prebuild": "node scripts/generate-feature-flags-rss.js",
78
"docusaurus": "docusaurus",
89
"start": "docusaurus start --host 0.0.0.0",
910
"build": "export NODE_OPTIONS=--max-old-space-size=7296 && DOCUSAURUS_IGNORE_SSG_WARNINGS=true docusaurus build",
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
const fs = require('fs-extra');
2+
const path = require('path');
3+
const { Feed } = require('feed');
4+
5+
function filterAndSortLast3Months(entries) {
6+
const now = new Date();
7+
const threeMonthsAgo = new Date();
8+
threeMonthsAgo.setMonth(now.getMonth() - 3);
9+
const filtered = entries.filter(entry => {
10+
const entryDate = new Date(entry.gaStartDate);
11+
return entryDate >= threeMonthsAgo;
12+
});
13+
filtered.sort((a, b) => new Date(b.gaStartDate) - new Date(a.gaStartDate));
14+
return filtered;
15+
}
16+
17+
// WARNING: This plugin generates the RSS file in postBuild, so it will NOT be available in dev mode (docusaurus start),
18+
// and links to /feature-flags/rss.xml will be flagged as broken unless onBrokenLinks is set to 'warn'.
19+
20+
async function featureFlagsRssPlugin(context, options) {
21+
return {
22+
name: 'feature-flags-rss-plugin',
23+
async postBuild({ outDir }) {
24+
const jsonPath = path.join(
25+
context.siteDir,
26+
'feature-flags/static/ff-ga-feed.json'
27+
);
28+
if (!fs.existsSync(jsonPath)) {
29+
console.warn('[feature-flags-rss-plugin] JSON file not found:', jsonPath);
30+
return;
31+
}
32+
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
33+
const filtered = filterAndSortLast3Months(data);
34+
if (!filtered || filtered.length === 0) {
35+
console.warn('[feature-flags-rss-plugin] No entries for RSS feed. Skipping RSS file generation.');
36+
return;
37+
}
38+
const siteUrl = context.siteConfig.url || '';
39+
const baseUrl = context.siteConfig.baseUrl || '/';
40+
const rssFeed = new Feed({
41+
title: 'Feature Flags GA RSS Feed',
42+
id: siteUrl + baseUrl + 'feature-flags/rss.xml',
43+
link: siteUrl + baseUrl + 'feature-flags/rss.xml',
44+
updated: new Date(),
45+
feedLinks: {
46+
rss: siteUrl + baseUrl + 'feature-flags/rss.xml',
47+
},
48+
});
49+
filtered.forEach(item => {
50+
rssFeed.addItem({
51+
title: item.flagKey,
52+
id: item.flagKey,
53+
link: siteUrl + baseUrl + 'feature-flags/',
54+
description: item.description,
55+
date: new Date(item.gaStartDate),
56+
category: [
57+
{
58+
name: item.module,
59+
term: item.module,
60+
},
61+
],
62+
});
63+
});
64+
const outputPathRSS = path.join(outDir, 'feature-flags', 'rss.xml');
65+
fs.ensureDirSync(path.dirname(outputPathRSS));
66+
fs.writeFileSync(outputPathRSS, rssFeed.rss2());
67+
console.log('[feature-flags-rss-plugin] RSS feed generated at', outputPathRSS);
68+
},
69+
};
70+
}
71+
72+
module.exports = featureFlagsRssPlugin;

scripts/generate-feature-flags-rss.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const fs = require('fs-extra');
2+
const path = require('path');
3+
const { Feed } = require('feed');
4+
5+
const jsonPath = path.join(__dirname, '../feature-flags/static/ff-ga-feed.json');
6+
const outputPath = path.join(__dirname, '../build/feature-flags/rss.xml');
7+
const siteUrl = 'https://developer.harness.io';
8+
const baseUrl = '/';
9+
10+
if (!fs.existsSync(jsonPath)) {
11+
console.warn('[ff-ga-rss] JSON file not found:', jsonPath);
12+
process.exit(0);
13+
}
14+
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
15+
if (!Array.isArray(data) || data.length === 0) {
16+
console.warn('[ff-ga-rss] No entries for RSS feed. Skipping RSS file generation.');
17+
process.exit(0);
18+
}
19+
const feed = new Feed({
20+
title: 'Feature Flags GA RSS Feed',
21+
id: siteUrl + baseUrl + 'feature-flags/rss.xml',
22+
link: siteUrl + baseUrl + 'feature-flags/rss.xml',
23+
updated: new Date(),
24+
feedLinks: {
25+
rss: siteUrl + baseUrl + 'feature-flags/rss.xml',
26+
},
27+
});
28+
data.forEach(item => {
29+
feed.addItem({
30+
title: item.flagKey,
31+
id: item.flagKey,
32+
link: siteUrl + baseUrl + 'feature-flags/',
33+
description: item.description,
34+
date: new Date(item.gaStartDate),
35+
category: [
36+
{
37+
name: item.module,
38+
term: item.module,
39+
},
40+
],
41+
});
42+
});
43+
fs.ensureDirSync(path.dirname(outputPath));
44+
fs.writeFileSync(outputPath, feed.rss2());
45+
console.log('[ff-ga-rss] RSS feed generated at', outputPath);
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from 'react';
2+
import Link from '@docusaurus/Link';
3+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
4+
import styles from './ga-list.module.css';
5+
import releaseNotesStyles from '@site/src/components/ReleaseNotes/styles.module.scss';
6+
7+
function FeatureFlagsGATable({ flags }) {
8+
return (
9+
<div style={{overflowX: 'auto', marginTop: '1.5rem', marginBottom: '2rem'}}>
10+
<table style={{width: '100%', borderCollapse: 'collapse', background: 'white', boxShadow: '0 1.5px 3px 0 rgb(0 0 0 / 8%)'}}>
11+
<thead>
12+
<tr>
13+
<th>Flag Key</th>
14+
<th>Description</th>
15+
<th>GA Start Date</th>
16+
<th>Module</th>
17+
</tr>
18+
</thead>
19+
<tbody>
20+
{flags.map((flag) => (
21+
<tr key={flag.flagKey}>
22+
<td><b>{flag.flagKey}</b></td>
23+
<td>{flag.description}</td>
24+
<td>{new Date(flag.gaStartDate).toLocaleDateString()}</td>
25+
<td>{flag.module}</td>
26+
</tr>
27+
))}
28+
</tbody>
29+
</table>
30+
</div>
31+
);
32+
}
33+
34+
export default function FeatureFlagsGAListPage({ flags = [], loading = false, error = null, compact = false }) {
35+
const { siteConfig: { baseUrl = '/' } = {} } = useDocusaurusContext();
36+
if (loading) return <p>Loading...</p>;
37+
if (error) return <p style={{ color: 'red' }}>{error}</p>;
38+
if (compact) {
39+
return <FeatureFlagsGATable flags={flags} />;
40+
}
41+
return (
42+
<div className="container">
43+
<div className={styles.topSection}>
44+
<div className={styles.spaceBetween}>
45+
<div className={releaseNotesStyles.btnContainer}>
46+
<Link href={'https://developer.harness.io/feature-flags/rss.xml'}>
47+
<button className={releaseNotesStyles.btn}>
48+
<img src={`${baseUrl}img/icon_square-rss.svg`} alt="Atom" />
49+
Subscribe via Atom
50+
</button>
51+
</Link>
52+
</div>
53+
</div>
54+
<div className={styles.spaceBetween}>
55+
<div className={styles.content}>
56+
<p>
57+
This page lists all Feature Flags that have reached General Availability (GA) in the last several months. You can track when a flag was GA'd, view its description, and filter by module. For a machine-readable feed, see the Atom link above.
58+
</p>
59+
</div>
60+
</div>
61+
</div>
62+
<FeatureFlagsGATable flags={flags} />
63+
</div>
64+
);
65+
}

0 commit comments

Comments
 (0)