Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ const config: Config = {
customFields: {
SEGMENT_API_KEY: process.env.SEGMENT_API_KEY,
HARNESS_GENERIC_READ_ONLY_KEY: process.env.HARNESS_GENERIC_READ_ONLY_KEY,
future: {
v4: true,
experimental_faster: true,
},
},

//Mermaid Diagram Functionality
Expand All @@ -47,10 +51,6 @@ const config: Config = {
locales: ['en'],
},

future: {
experimental_faster: true,
},

presets: [
[
'classic',
Expand Down Expand Up @@ -439,6 +439,10 @@ const config: Config = {
label: 'Feature Requests',
to: 'https://ideas.harness.io',
},
{
label: 'Feature Flags GA List',
to: '/feature-flags',
},
{
label: 'Instructor-Led Training',
to: '/university?ilt',
Expand Down Expand Up @@ -528,6 +532,16 @@ const config: Config = {
},
},
],
[
path.resolve(__dirname, './plugins/docs-rss-plugin'),
{
id: 'feature-flags',
path: 'feature-flags',
routeBasePath: 'feature-flags',
exclude: ['**/shared/**', '**/static/**', '**/content/**'],
editUrl: 'https://github.com/harness/developer-hub/tree/main',
},
],
// redirect plugin start
[
path.resolve(__dirname, './plugins/docsEnhanced-plugin'),
Expand Down Expand Up @@ -613,6 +627,7 @@ const config: Config = {
path.join(__dirname, '/plugins/utmcookie-plugin'),
path.join(__dirname, '/plugins/focusOnAnchor-plugin'),
path.join(__dirname, '/plugins/feedback-plugin'),
path.join(__dirname, '/plugins/feature-flags-rss-plugin'),
],
clientModules: [
path.join(__dirname, '/client-modules/searchBar'),
Expand Down
13 changes: 13 additions & 0 deletions feature-flags/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
sidebar_position: 0
hide_table_of_contents: true
hide_title: true
title: Feature Flags
slug: /
date: 2024-11-13T10:00
---

import FeatureFlagsLanding from '@site/src/components/FeatureFlagGA/FeatureFlagsLanding';
import ffGAFeed from './static/ff-ga-feed.json';

<FeatureFlagsLanding staticFlags={ffGAFeed} />
128 changes: 128 additions & 0 deletions feature-flags/static/ff-ga-feed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
[
{
"flagKey": "CDS_ADD_DEPLOYMENT_FREEZE_BYPASS_AUDIT",
"description": "Enables audit logging for deployment freeze bypass actions.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_DEPLOYMENT_FREEZE_GRANULAR_RBAC",
"description": "Provides granular role-based access control for deployment freeze operations based on environment type.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_GITLAB_TRIGGER_TAG_EVENT",
"description": "Enables GitLab tag event triggers for pipelines.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_TF_POLICY_EVALUATION",
"description": "Enables Terraform policy evaluation in Continuous Delivery workflows.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_TEXTAREA_FOR_OVERRIDE_VARIABLES",
"description": "Provides textarea input for override variables in deployment configurations.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_TAS_LOGIN_OPTIMIZATION",
"description": "Optimizes Tanzu Application Service (TAS) login performance and reliability by reducing the number of CLI initialisation calls.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_SUPPORT_TF_CLOUD_PLAN_REFRESH_TYPE",
"description": "Adds support for Terraform Cloud plan refresh type operations.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_UI_ENABLE_DISALLOWED_USER_EMAILS_IN_APPROVAL_STEP",
"description": "Enables configuration to block certain users from approving in Harness Approval steps based on emails.",
"gaStartDate": "2025-09-15",
"module": "Pipeline"
},
{
"flagKey": "CDS_AZURE_OIDC_AUTHENTICATION",
"description": "Enables OIDC authentication for Azure connectors.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_GCP_LIST_PROJECTS_AUTH_FIX",
"description": "Fixes authentication issues when listing Google Cloud Platform projects.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_GCP_OIDC_CONNECTOR_CROSS_PROJECT_ACCESS",
"description": "Enables cross-project access for Google Cloud Platform connectors.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_OPTIONAL_VALUES_YAML",
"description": "Enables optional values.yaml files in K8s & Helm deployments.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_ENFORCE_GIT_EXPERIENCE",
"description": "Enforces Git-based experience for CD entities such as service, environment, infrastructure and override configurations.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_K8S_DETAILED_LOGS",
"description": "Provides detailed logging for Kubernetes operations in CD.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_INFRA_DEFINITION_VALIDATION",
"description": "Enforces certain validation for infrastructure definitions in CD.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_USE_SECONDARY_NODE_FOR_TIMESCALE_QUERIES",
"description": "Internal optimisation to use secondary database nodes for TimescaleDB queries to improve performance.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_ADD_EXPRESSION_RESOLUTION_FOR_OVERRIDES_V2_AT_SERVICE_STEP",
"description": "Fixes a bug that resolves expressions in overrides at the service step.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_OVERRIDES_GITX",
"description": "Enables Git experience for service and infrastructure overrides management.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_EVENT_BRIDGE_WEBHOOK",
"description": "Enables Event Relay triggers for pipelines.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_SERVICE_INFRA_FAILURE_STRATEGY",
"description": "Implements failure strategies for service and infrastructure deployment steps.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
},
{
"flagKey": "CDS_OVERRIDES_V2_IDENTIFIER_SUPPORT",
"description": "Adds identifier support for version 2 service and infrastructure overrides.",
"gaStartDate": "2025-09-15",
"module": "Continuous Delivery"
}
]
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"license": "MIT",
"private": true,
"scripts": {
"prebuild": "node scripts/generate-feature-flags-rss.js",
"docusaurus": "docusaurus",
"start": "docusaurus start --host 0.0.0.0",
"build": "export NODE_OPTIONS=--max-old-space-size=7296 && DOCUSAURUS_IGNORE_SSG_WARNINGS=true docusaurus build",
Expand Down
72 changes: 72 additions & 0 deletions plugins/feature-flags-rss-plugin/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const fs = require('fs-extra');
const path = require('path');
const { Feed } = require('feed');

function filterAndSortLast3Months(entries) {
const now = new Date();
const threeMonthsAgo = new Date();
threeMonthsAgo.setMonth(now.getMonth() - 3);
const filtered = entries.filter(entry => {
const entryDate = new Date(entry.gaStartDate);
return entryDate >= threeMonthsAgo;
});
filtered.sort((a, b) => new Date(b.gaStartDate) - new Date(a.gaStartDate));
return filtered;
}

// WARNING: This plugin generates the RSS file in postBuild, so it will NOT be available in dev mode (docusaurus start),
// and links to /feature-flags/rss.xml will be flagged as broken unless onBrokenLinks is set to 'warn'.

async function featureFlagsRssPlugin(context, options) {
return {
name: 'feature-flags-rss-plugin',
async postBuild({ outDir }) {
const jsonPath = path.join(
context.siteDir,
'feature-flags/static/ff-ga-feed.json'
);
if (!fs.existsSync(jsonPath)) {
console.warn('[feature-flags-rss-plugin] JSON file not found:', jsonPath);
return;
}
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
const filtered = filterAndSortLast3Months(data);
if (!filtered || filtered.length === 0) {
console.warn('[feature-flags-rss-plugin] No entries for RSS feed. Skipping RSS file generation.');
return;
}
const siteUrl = context.siteConfig.url || '';
const baseUrl = context.siteConfig.baseUrl || '/';
const rssFeed = new Feed({
title: 'Feature Flags GA RSS Feed',
id: siteUrl + baseUrl + 'feature-flags/rss.xml',
link: siteUrl + baseUrl + 'feature-flags/rss.xml',
updated: new Date(),
feedLinks: {
rss: siteUrl + baseUrl + 'feature-flags/rss.xml',
},
});
filtered.forEach(item => {
rssFeed.addItem({
title: item.flagKey,
id: item.flagKey,
link: siteUrl + baseUrl + 'feature-flags/',
description: item.description,
date: new Date(item.gaStartDate),
category: [
{
name: item.module,
term: item.module,
},
],
});
});
const outputPathRSS = path.join(outDir, 'feature-flags', 'rss.xml');
fs.ensureDirSync(path.dirname(outputPathRSS));
fs.writeFileSync(outputPathRSS, rssFeed.rss2());
console.log('[feature-flags-rss-plugin] RSS feed generated at', outputPathRSS);
},
};
}

module.exports = featureFlagsRssPlugin;
45 changes: 45 additions & 0 deletions scripts/generate-feature-flags-rss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const fs = require('fs-extra');
const path = require('path');
const { Feed } = require('feed');

const jsonPath = path.join(__dirname, '../feature-flags/static/ff-ga-feed.json');
const outputPath = path.join(__dirname, '../build/feature-flags/rss.xml');
const siteUrl = 'https://developer.harness.io';
const baseUrl = '/';

if (!fs.existsSync(jsonPath)) {
console.warn('[ff-ga-rss] JSON file not found:', jsonPath);
process.exit(0);
}
const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
if (!Array.isArray(data) || data.length === 0) {
console.warn('[ff-ga-rss] No entries for RSS feed. Skipping RSS file generation.');
process.exit(0);
}
const feed = new Feed({
title: 'Feature Flags GA RSS Feed',
id: siteUrl + baseUrl + 'feature-flags/rss.xml',
link: siteUrl + baseUrl + 'feature-flags/rss.xml',
updated: new Date(),
feedLinks: {
rss: siteUrl + baseUrl + 'feature-flags/rss.xml',
},
});
data.forEach(item => {
feed.addItem({
title: item.flagKey,
id: item.flagKey,
link: siteUrl + baseUrl + 'feature-flags/',
description: item.description,
date: new Date(item.gaStartDate),
category: [
{
name: item.module,
term: item.module,
},
],
});
});
fs.ensureDirSync(path.dirname(outputPath));
fs.writeFileSync(outputPath, feed.rss2());
console.log('[ff-ga-rss] RSS feed generated at', outputPath);
65 changes: 65 additions & 0 deletions src/components/FeatureFlagGA/FeatureFlagsGAListPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import styles from './ga-list.module.css';
import releaseNotesStyles from '@site/src/components/ReleaseNotes/styles.module.scss';

function FeatureFlagsGATable({ flags }) {
return (
<div style={{overflowX: 'auto', marginTop: '1.5rem', marginBottom: '2rem'}}>
<table style={{width: '100%', borderCollapse: 'collapse', background: 'white', boxShadow: '0 1.5px 3px 0 rgb(0 0 0 / 8%)'}}>
<thead>
<tr>
<th>Flag Key</th>
<th>Description</th>
<th>GA Start Date</th>
<th>Module</th>
</tr>
</thead>
<tbody>
{flags.map((flag) => (
<tr key={flag.flagKey}>
<td><b>{flag.flagKey}</b></td>
<td>{flag.description}</td>
<td>{new Date(flag.gaStartDate).toLocaleDateString()}</td>
<td>{flag.module}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}

export default function FeatureFlagsGAListPage({ flags = [], loading = false, error = null, compact = false }) {
const { siteConfig: { baseUrl = '/' } = {} } = useDocusaurusContext();
if (loading) return <p>Loading...</p>;
if (error) return <p style={{ color: 'red' }}>{error}</p>;
if (compact) {
return <FeatureFlagsGATable flags={flags} />;
}
return (
<div className="container">
<div className={styles.topSection}>
<div className={styles.spaceBetween}>
<div className={releaseNotesStyles.btnContainer}>
<Link href={'https://developer.harness.io/feature-flags/rss.xml'}>
<button className={releaseNotesStyles.btn}>
<img src={`${baseUrl}img/icon_square-rss.svg`} alt="Atom" />
Subscribe via Atom
</button>
</Link>
</div>
</div>
<div className={styles.spaceBetween}>
<div className={styles.content}>
<p>
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.
</p>
</div>
</div>
</div>
<FeatureFlagsGATable flags={flags} />
</div>
);
}
Loading