Skip to content

Commit

Permalink
Develop (#190)
Browse files Browse the repository at this point in the history
* Exclude (#181)

Updates the code that reads files to take into account a list of excluded glob patterns

* Changelog (#182)

* Fixing wiki links

* Releasing new version

* Updating the reflection version dependency (#189)

* Ability to skip changelog creation when there are no changes. (#191)

* Changelog example documentation

* Run specific command in multi config (#192)

* When creating a multi-config configuration, a single command can still be specified

* When creating a multi-config configuration, a single command can still be specified

* Releasing version
  • Loading branch information
cesarParra authored Oct 10, 2024
1 parent 1112aea commit 26d2f6b
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 87 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ apexdocs openapi -s force-app -t docs -n MyNamespace --title "My Custom OpenApi
| `--targetDir` | `-t` | The directory location where the changelog file will be generated. | `./docs/` | No |
| `--fileName` | N/A | The name of the changelog file to be generated. | `changelog` | No |
| `--scope` | N/A | The list of scope to respect when generating the changelog. | ['global'] | No |
| `--skipIfNoChanges` | N/A | Whether to skip generating the changelog if there are no changes. | `true` | No |

#### Sample Usage

Expand Down Expand Up @@ -263,9 +264,8 @@ export default {

Then you only need to run the top level `apexdocs` command, and it will generate both types of documentation.

```bash
apexdocs
```
Note that you can still run the individual commands if you only want to generate one type of documentation by
providing the subcommand, e.g `apexdocs markdown` or `apexdocs changelog`.

### Excluding Tags from Appearing in the Documentation

Expand Down
63 changes: 63 additions & 0 deletions examples/changelog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Changelog Example

This project contains an example on how to generate a changelog using ApexDocs.'

It has 2 directories: `previous`, which contains the previous version of the project, and `current`, which contains the current version of the project.

By running the following command, you can generate a changelog between the two versions:

```bash
apexdocs changelog --previousVersionDir previous --currentVersionDir current
```

---

## Generating PR Comments with Changelog Information

One example of how to use the changelog feature is to generate a changelog for a pull request.

You can achieve this through Github Actions by using a workflow that looks as follows:

```yaml
on:
pull_request:
branches: [ main ]
types: [ opened, reopened, synchronize, closed ]

jobs:
comment-pr:
runs-on: ubuntu-latest
name: Comment PR
permissions:
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Checkout previous version
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.base.ref }}
path: previous

- uses: actions/setup-node@v2
with:
node-version: "20"

- name: Install dependencies
run: npm install

- name: Install ApexDocs globally
run: npm install @cparra/apexdocs --global

- name: Generate changelog
# Change the previousVersionDir and currentVersionDir to match your project structure
run: apexdocs changelog --currentVersionDir force-app --previousVersionDir './previous/force-app' --targetDir './changelog'

- name: Comment PR
uses: thollander/actions-comment-pull-request@v2
with:
# Providing a comment_tag will update the comment if it already exists
comment_tag: 'changelog'
filePath: './changelog/changelog.md'
```
14 changes: 7 additions & 7 deletions examples/vitepress/docs/.vitepress/cache/deps/_metadata.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
{
"hash": "98853dc2",
"hash": "f2216e85",
"configHash": "7f7b0dad",
"lockfileHash": "2250ed1c",
"browserHash": "0b73d2e4",
"lockfileHash": "76121266",
"browserHash": "441a8d6a",
"optimized": {
"vue": {
"src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "dd9e77dd",
"fileHash": "885cbaa9",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "522b9fac",
"fileHash": "ff3ba36c",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "5b6312b7",
"fileHash": "b6cc6d79",
"needsInterop": false
},
"@theme/index": {
"src": "../../../../node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
"fileHash": "8adc2f2d",
"fileHash": "6b17bcd7",
"needsInterop": false
}
},
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cparra/apexdocs",
"version": "3.2.2",
"version": "3.3.0",
"description": "Library with CLI capabilities to generate documentation for Salesforce Apex classes.",
"keywords": [
"apex",
Expand Down Expand Up @@ -61,7 +61,7 @@
]
},
"dependencies": {
"@cparra/apex-reflection": "2.13.1",
"@cparra/apex-reflection": "2.15.0",
"@types/js-yaml": "^4.0.9",
"@types/yargs": "^17.0.32",
"chalk": "^4.1.2",
Expand Down
1 change: 0 additions & 1 deletion src/application/Apexdocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ async function processChangeLog(config: UserDefinedChangelogConfig) {
return pipe(
TE.tryCatch(loadFiles, (e) => new FileReadingError('An error occurred while reading files.', e)),
TE.flatMap(([previous, current]) => changelog(previous, current, config)),
TE.map(() => '✔️ Changelog generated successfully!'),
TE.mapLeft(toErrors),
);
}
Expand Down
17 changes: 12 additions & 5 deletions src/application/generators/changelog.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import { pipe } from 'fp-ts/function';
import { PageData, UnparsedSourceFile, UserDefinedChangelogConfig } from '../../core/shared/types';
import { PageData, Skip, UnparsedSourceFile, UserDefinedChangelogConfig } from '../../core/shared/types';
import * as TE from 'fp-ts/TaskEither';
import { writeFiles } from '../file-writer';
import { ChangeLogPageData, generateChangeLog } from '../../core/changelog/generate-change-log';
import { FileWritingError } from '../errors';
import { isSkip } from '../../core/shared/utils';

export default function generate(
oldBundles: UnparsedSourceFile[],
newBundles: UnparsedSourceFile[],
config: UserDefinedChangelogConfig,
) {
return pipe(
generateChangeLog(oldBundles, newBundles, config),
TE.flatMap((files) => writeFilesToSystem(files, config.targetDir)),
);
function handleFile(file: ChangeLogPageData | Skip) {
if (isSkip(file)) {
return TE.right('✔️ Done! Skipped writing files to the system.');
}

return writeFilesToSystem(file, config.targetDir);
}

return pipe(generateChangeLog(oldBundles, newBundles, config), TE.flatMap(handleFile));
}

function writeFilesToSystem(pageData: ChangeLogPageData, outputDir: string) {
return pipe(
[pageData],
(files) => writeFiles(files as PageData[], outputDir),
TE.map(() => '✔️ Changelog generated successfully!'),
TE.mapLeft((error) => {
return new FileWritingError('An error occurred while writing files to the system.', error);
}),
Expand Down
13 changes: 11 additions & 2 deletions src/cli/__tests__/args/multiple-command-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {

describe('when extracting arguments', () => {
describe('and a configuration is provided for multiple commands', () => {
it('errors when a command was still passed through the cli', async () => {
it('if a subcommand was specified through the cli, it only extract the specified subcommand', async () => {
function getFromProcess() {
return ['markdown'];
}
Expand All @@ -20,13 +20,22 @@ describe('when extracting arguments', () => {
markdown: {
sourceDir: 'force-app',
},
openapi: {
sourceDir: 'force-app',
},
},
});
}

const result = await extractArgs(getFromProcess, extractConfig);

expect(E.isLeft(result)).toBeTruthy();
assertEither(result, (configs) => {
expect(configs).toHaveLength(1);
expect(configs[0].targetGenerator).toEqual('markdown');

const markdownConfig = configs[0] as UserDefinedMarkdownConfig;
expect(markdownConfig.sourceDir).toEqual('force-app');
});
});

it('extracts multiple configurations', async () => {
Expand Down
76 changes: 40 additions & 36 deletions src/cli/args.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { cosmiconfig } from 'cosmiconfig';
import * as yargs from 'yargs';
import yargs = require('yargs');
import * as E from 'fp-ts/Either';
import {
Generators,
Expand Down Expand Up @@ -108,26 +108,41 @@ type ConfigByGenerator = {
function extractArgsForCommandsProvidedInConfig(
extractFromProcessFn: ExtractArgsFromProcess,
config: ConfigByGenerator,
) {
const configs = Object.entries(config).map(([generator, generatorConfig]) => {
switch (generator as Generators) {
case 'markdown':
return pipe(
validateMultiCommandConfig(extractFromProcessFn, 'markdown', generatorConfig),
E.map(() => ({ ...configOnlyMarkdownDefaults, ...generatorConfig })),
);
case 'openapi':
return pipe(
validateMultiCommandConfig(extractFromProcessFn, 'openapi', generatorConfig),
E.map(() => ({ ...configOnlyOpenApiDefaults, ...generatorConfig })),
);
case 'changelog':
return pipe(
validateMultiCommandConfig(extractFromProcessFn, 'changelog', generatorConfig),
E.map(() => ({ ...configOnlyChangelogDefaults, ...generatorConfig })),
);
}
});
): E.Either<Error, readonly UserDefinedConfig[]> {
const providedThroughCli = yargs.parseSync(extractFromProcessFn());
const hasACommandBeenProvided = providedThroughCli._.length > 0;

const configs = Object.entries(config)
// If no specific command was provided through the CLI, we will generate all the commands.
// Otherwise, we only want to generate the command that was provided.
.filter(([generator]) => (hasACommandBeenProvided ? providedThroughCli._[0] === generator : true))
.map(([generator, generatorConfig]) => {
switch (generator as Generators) {
case 'markdown':
return pipe(
extractMultiCommandConfig(extractFromProcessFn, 'markdown', generatorConfig),
E.map((cliArgs) => {
console.log('markdown', cliArgs);
return cliArgs;
}),
E.map((cliArgs) => ({ ...configOnlyMarkdownDefaults, ...generatorConfig, ...cliArgs })),
);
case 'openapi':
return pipe(
extractMultiCommandConfig(extractFromProcessFn, 'openapi', generatorConfig),
E.map((cliArgs) => ({ ...configOnlyOpenApiDefaults, ...generatorConfig, ...cliArgs })),
);
case 'changelog':
return pipe(
extractMultiCommandConfig(extractFromProcessFn, 'changelog', generatorConfig),
E.map((cliArgs) => {
console.log('changelog', cliArgs);
return cliArgs;
}),
E.map((cliArgs) => ({ ...configOnlyChangelogDefaults, ...generatorConfig, ...cliArgs })),
);
}
});

return E.sequenceArray(configs);
}
Expand Down Expand Up @@ -192,7 +207,7 @@ function extractYargsDemandingCommand(extractFromProcessFn: ExtractArgsFromProce
.parseSync(extractFromProcessFn());
}

function validateMultiCommandConfig(
function extractMultiCommandConfig(
extractFromProcessFn: ExtractArgsFromProcess,
command: Generators,
config: UserDefinedConfig,
Expand All @@ -209,25 +224,14 @@ function validateMultiCommandConfig(
}

const options = getOptions(command);
console.log('config', config);
return E.tryCatch(() => {
yargs
return yargs(extractFromProcessFn())
.config(config)
.options(options)
.check((argv) => {
// we should not be receiving a command here
// since this is a multi-command config
if (argv._.length > 0) {
throw new Error(
`Unexpected command "${argv._[0]}".
The command name should be provided in the configuration when using the current configuration format.`,
);
} else {
return true;
}
})
.fail((msg) => {
throw new Error(`Invalid configuration for command "${command}": ${msg}`);
})
.parse(extractFromProcessFn());
.parseSync();
}, E.toError);
}
5 changes: 5 additions & 0 deletions src/cli/commands/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ export const changeLogOptions: { [key: string]: Options } = {
'Values should be separated by a space, e.g --scope global public namespaceaccessible. ' +
'Annotations are supported and should be passed lowercased and without the @ symbol, e.g. namespaceaccessible auraenabled.',
},
skipIfNoChanges: {
type: 'boolean',
default: changeLogDefaults.skipIfNoChanges,
describe: 'Skip the changelog generation if there are no changes between the previous and current version.',
},
};
Loading

0 comments on commit 26d2f6b

Please sign in to comment.