Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Develop Ruleset Live Contexts** — Required checks now reference checks that actually run; dropped the unused merge-queue rule. (#3450)
- **Footer Dedup Asterisk Match** — Footer dedup patterns now match asterisk-wrapped footers as well as underscore-wrapped ones, keeping ensureFooter() idempotent. (#3443)
- **Footer Config Path Fixed** — Footer generation now reads the real `.github/footers.yml` path and fallback block, instead of always using generic placeholder text. (#3446)
- **Branding Agent Footer Config Path Fixed** — Corrected the same stale config path and dedup regex bugs in `branding.agent.js`. (#3456)
- **Bot Commits via Pull Requests** — Metrics, documentation and maintenance bots now open fixed-branch pull requests instead of pushing to develop; metrics run daily. ([PR #3410](https://github.com/lightspeedwp/.github/pull/3410))
- **Metrics PR Runs CI via App Token** — The metrics aggregator mints a GitHub App token for its fixed-branch PR and drops `[skip ci]`, so required checks report and the merge queue can take it.
- **Bot PR Hygiene Pass** — Docs bot PR bodies now carry all required template sections, the docs bot is exempt from the changelog requirement like Dependabot, and both token steps use the modern client-id input.
Expand Down
70 changes: 70 additions & 0 deletions scripts/agents/__tests__/branding.agent.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const fs = require('fs');
const os = require('os');
const path = require('path');

// Isolates these tests from the real .github/footers.yml and from
// process.cwd() -- loadFooterConfig() reads process.cwd() + '.github/footers.yml'
// on every call, so each test gets its own fixture directory with that
// same layout and mocks cwd to point there for the test's duration.
// Phrases must match one of FOOTER_PATTERNS' hardcoded literal fragments
// (branding.agent.js's dedup regex recognizes specific English phrases,
// not arbitrary config content) -- "Prefer a guided" and "Need help?" are
// both entries in FOOTER_PATTERNS, same as the real .github/footers.yml.
const FIXTURE_CONFIG = [
'categories:',
' docs:',
' phrases:',
' - "Prefer a guided setup? Book a consult."',
'default:',
' phrases:',
' - "Need help? Say hi."',
'',
].join('\n');

function setUpFixtureCwd() {
const fixtureDir = fs.mkdtempSync(path.join(os.tmpdir(), 'branding-agent-fixture-'));
fs.mkdirSync(path.join(fixtureDir, '.github'), { recursive: true });
fs.writeFileSync(path.join(fixtureDir, '.github', 'footers.yml'), FIXTURE_CONFIG);
return jest.spyOn(process, 'cwd').mockReturnValue(fixtureDir);
}

describe('branding.agent footer functions', () => {
let cwdSpy;

afterEach(() => {
cwdSpy?.mockRestore();
});

test('loadFooterConfig reads .github/footers.yml, not .github/automation/footers.yml', async () => {
cwdSpy = setUpFixtureCwd();
const { getFooterPhrases } = await import('../branding.agent.js');
expect(getFooterPhrases('docs')).toEqual(['Prefer a guided setup? Book a consult.']);
});

test('getFooterPhrases falls back to the top-level default for an unknown category', async () => {
cwdSpy = setUpFixtureCwd();
const { getFooterPhrases } = await import('../branding.agent.js');
expect(getFooterPhrases('unknown')).toEqual(['Need help? Say hi.']);
});

test('ensureFooter is idempotent across repeated runs, including asterisk-wrapped footers', async () => {
cwdSpy = setUpFixtureCwd();
const { ensureFooter } = await import('../branding.agent.js');
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'branding-agent-idempotent-'));
const filePath = path.join(tmpDir, 'test.md');

fs.writeFileSync(
filePath,
'# Test\n\nSome content.\n\n*Docs signed by 🤖 Copilot for LightSpeedWP – always fresh!*\n'
);

ensureFooter(filePath, { category: 'docs', seed: 'x' });
const afterFirstRun = fs.readFileSync(filePath, 'utf8');

ensureFooter(filePath, { category: 'docs', seed: 'x' });
const afterSecondRun = fs.readFileSync(filePath, 'utf8');

expect(afterFirstRun).toBe(afterSecondRun);
expect(afterSecondRun.trim().split(/\n\s*\n/)).toHaveLength(3);
});
});
Loading
Loading