diff --git a/FSharp.Formatting.sln b/FSharp.Formatting.sln index 76b0b62a2..dcbafb0a0 100644 --- a/FSharp.Formatting.sln +++ b/FSharp.Formatting.sln @@ -33,6 +33,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{312E452A-1 docs\markdown.fsx = docs\markdown.fsx docs\styling.md = docs\styling.md docs\upgrade.md = docs\upgrade.md + docs\users.md = docs\users.md + docs\zero-to-hero.md = docs\zero-to-hero.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{D0550510-0DCE-4B40-B4FB-091668E1C5FD}" diff --git a/docs/content/img/github-pages-settings.png b/docs/content/img/github-pages-settings.png new file mode 100644 index 000000000..a7657705d Binary files /dev/null and b/docs/content/img/github-pages-settings.png differ diff --git a/docs/users.md b/docs/users.md new file mode 100644 index 000000000..b43dc684e --- /dev/null +++ b/docs/users.md @@ -0,0 +1,36 @@ +--- +category: Documentation +categoryindex: 1 +index: 8 +--- +# Users of FSharp.Formatting + +The FSharp.Formatting documentation tool is widely used within the F# community. +Here is a non-exhaustive list of projects: + + + + +| Project name | | Repository | Note | +|-----------------------------------------------------------------------------|:--|--------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| [FSharp.Formatting](https://fsprojects.github.io/FSharp.Formatting/) | | [https://github.com/fsprojects/FSharp.Formatting/](https://github.com/fsprojects/FSharp.Formatting/) | | +| [F# compiler guide](https://fsharp.github.io/fsharp-compiler-docs/) | | [https://github.com/dotnet/fsharp/](https://github.com/dotnet/fsharp/) | The documentation is generated and published from [https://github.com/fsharp/fsharp-compiler-docs](https://github.com/fsharp/fsharp-compiler-docs) | +| [F# Core Library Documentation](https://fsharp.github.io/fsharp-core-docs/) | | [https://github.com/dotnet/fsharp/](https://github.com/dotnet/fsharp/) | The documentation is generated and published from [https://github.com/fsharp/fsharp-core-docs](https://github.com/fsharp/fsharp-core-docs) | +| [FsLexYacc](https://fsprojects.github.io/FsLexYacc) | | [https://github.com/fsprojects/fslexYacc/](https://github.com/fsprojects/fslexYacc/) | | +| [FSharp.Data](https://fsprojects.github.io/FSharp.Data/) | | [https://github.com/fsprojects/FSharp.Data/](https://github.com/fsprojects/FSharp.Data/) | | +| [Plotly.NET](https://plotly.net/) | | [https://github.com/plotly/Plotly.NET](https://github.com/plotly/Plotly.NET) | | +| [FSharp.Stats](https://fslab.org/FSharp.Stats/) | | [https://github.com/fslaborg/FSharp.Stats/](https://github.com/fslaborg/FSharp.Stats/) | | +| [FsHttp](https://fsprojects.github.io/FsHttp/) | | [https://github.com/fsprojects/FsHttp/](https://github.com/fsprojects/FsHttp/) | | +| [Fantomas](https://fsprojects.github.io/fantomas/docs/) | | [https://github.com/fsprojects/fantomas/](https://github.com/fsprojects/fantomas/) | | +| [Telplin](https://nojaf.com/telplin/docs/) | | [https://github.com/nojaf/telplin/](https://github.com/nojaf/telplin/) | | +| [FSharp.Data.Fred](https://github.com/nhirschey/FSharp.Data.Fred/) | | [https://github.com/nhirschey/FSharp.Data.Fred/](https://github.com/nhirschey/FSharp.Data.Fred/) | | +| [N Hirschey Teaching](https://nhirschey.github.io/Teaching/) | | [https://github.com/nhirschey/Teaching](https://github.com/nhirschey/Teaching) | | +| [FsUnit](https://fsprojects.github.io/FsUnit/) | | [https://github.com/fsprojects/FsUnit](https://github.com/fsprojects/FsUnit) | | +| [FAKE](https://fake.build/) | | [https://github.com/fsprojects/FAKE](https://github.com/fsprojects/FAKE) | | +| [FSharp.Data.GraphQL](https://fsprojects.github.io/FSharp.Data.GraphQL/) | | [https://github.com/fsprojects/FSharp.Data.GraphQL](https://github.com/fsprojects/FSharp.Data.GraphQL) | | diff --git a/docs/zero-to-hero.md b/docs/zero-to-hero.md new file mode 100644 index 000000000..2234a3407 --- /dev/null +++ b/docs/zero-to-hero.md @@ -0,0 +1,261 @@ +--- +category: Documentation +categoryindex: 1 +index: 9 +--- +# From zero to hero: deploying to GitHub Pages + +This guide is meant for a typical setup of open-source projects on GitHub. +We start from a repository without any documentation and aim to end up with a published website on [GitHub Pages](https://pages.github.com/). + +## Install the local tool + +If you don't have a [dotnet tool manifest](https://learn.microsoft.com/en-us/dotnet/core/tools/local-tools-how-to-use#create-a-manifest-file), you can create one using `dotnet new tool-manifest`. + +Next, we can install [fsdocs-tool](https://www.nuget.org/packages/fsdocs-tool/) using `dotnet tool install --local fsdocs-tool`. +It is recommended to install this tool as a local tool because it allows us to update to newer versions of the tool at our own pace. + +## Create the docs folder + +After we've installed the tool, we can run `dotnet fsdocs --help` and see the available commands. +Both `build` and `watch` will generate the documentation for a solution and an input folder. +The default folder for `--input` is the `./docs` folder, relative to the current working directory. + +Typically your project will be structured like: + +``` +/repository-root + YourSolution.sln + ./docs + index.md + other-file.md + ./src + ./Project1/Project1.fsproj + ./Project2/Project2.fsproj +``` + +It is recommended to have a single solution at the root. In some editors, it is more convenient to open a solution at the root, to easily manipulate any file in root repository folder. +When users clone your repository locally, they cannot be confused on how they need to open the project in their IDE. + +⚠️ Please avoid putting your solution in the `src` folder. When we open that solution, it can be more difficult to edit files in the `docs` folder, as we can sometimes only see the `src` folder. + +That being said, let's create the `docs` folder and a first Markdown file named `index.md`. +When `fsdocs` runs, it will transform this `index.md` file to `index.html`, which will be served at the root. + +We can put `# Hello world` in the markdown file for now. + +Having this in place, should already serve the first page when we start the `watch` command: + +> dotnet fsdocs watch + +Open [http://localhost:8901](http://localhost:8901) and you should see our first page! + +🪄 You might notice that there are some images missing. You can add these in the `docs` folder in the right location. + +## Generating API documentation + +By default, `fsdocs` will generate API documentation for the configured `--projects`. +When this flag is not specified, `fsdocs` will look for solutions or projects in the working directory. +It will filter these found projects, the requirements are: + +- Having `library` +- Having a binary, so you need to build your project first before the documentation can be generated. +- Not having `true` +- Having `true` + +🪄 If you made some changes in order to adhere to the rules, you may want to remove the `.fsdocs/cache` file. + +## Adding the missing properties + +After our initial `watch` run, you may have noticed that some links aren't working yet. +`License`, `Releases Notes` and `Source Repository` can be provided by setting MSBuild properties. + +You can either add these properties to a single `.fsproj` file, or more typically, add them to a [Directory.Build.props](https://learn.microsoft.com/visualstudio/msbuild/customize-by-directory) file. +The simplest `Directory.Build.props` file: + +```xml + + + https://github.com/fsprojects/FSharp.AWS.DynamoDB + https://github.com/fsprojects/FSharp.AWS.DynamoDB/blob/master/License.md + https://github.com/fsprojects/FSharp.AWS.DynamoDB/blob/master/RELEASE_NOTES.md + https://fsprojects.github.io/FSharp.AWS.DynamoDB + + +``` + +🪄 If you don't have any release notes yet, you could consider using [Ionide.KeepAChangelog](https://github.com/ionide/KeepAChangelog). + +Running `dotnet fsdocs watch` will now yield: + +``` + root --> https://github.com/fsprojects/FSharp.AWS.DynamoDB/ + ... + fsdocs-license-link --> https://github.com/fsprojects/FSharp.AWS.DynamoDB/blob/master/License.md + fsdocs-release-notes-link --> https://github.com/fsprojects/FSharp.AWS.DynamoDB/blob/master/RELEASE_NOTES.md + ... + fsdocs-repository-link --> https://github.com/fsprojects/FSharp.AWS.DynamoDB/ +``` + +⚠️ Again, you might need to remove `.fsdocs/cache` in order for changes to be picked up! + +`` is actually a very important property when you run `dotnet fsdocs build`. +`build` will generate static files for the targeted production environment. In our case, this will be GitHub Pages. + +Pages will host your files from https://github.com/user/project on `https://user.github.io/project/` by default. +You can change this by adding a custom domain so we need to be sure that all links and urls will be generated correctly during a build. + +Let's now run `dotnet fsdocs build`. + +`` will replace the `{{root}}` substitution, which is used all over the place in the default template. + +⚠️ You want to ensure that the static files in the `output` folder (after running the build) have the correct links. + +## Ignore generated files + +Alright, at this point we've made a lot of progress. If you are using `git` you want to add the following to your [.gitignore](https://git-scm.com/docs/gitignore) file. + +```.ignorelang +# FSharp.Formatting +.fsdocs/ +output/ +tmp/ +``` + +## Ship it! + +Once we are satisfied with our documentation, we want to publish it to GitHub Pages. +We can use [GitHub Actions](https://github.com/features/actions) to deploy our website. + +Deploy to Pages from GitHub Actions must be enabled in the repository settings: + +![Enable deploy from Actions](./content/img/github-pages-settings.png) + +The typical flow is to publish your documentation after a release or after new commits were added to the default branch. +Let's create a very basic Action that will deploy our website after pushing to main: + +Create a file `.github/workflows/docs.yml`: + +```yml +name: Docs + +# Trigger this Action when new code is pushed to the main branch +on: + push: + branches: + - main + +# We need some permissions to publish to Github Pages +permissions: + contents: write + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + # Checkout the source code + - uses: actions/checkout@v4 + # Setup dotnet, please use a global.json to ensure the right SDK is used! + - name: Setup .NET + uses: actions/setup-dotnet@v3 + # Restore the local tools + - name: Restore tools + run: dotnet tool restore + # Build the code for the API documentation + - name: Build code + run: dotnet build -c Release YourSolution.sln + # Generate the documentation files + - name: Generate the documentation' + run: dotnet fsdocs build --properties Configuration=Release + # Upload the static files + - name: Upload documentation + uses: actions/upload-pages-artifact@v2 + with: + path: ./output + + # GitHub Actions recommends deploying in a separate job. + deploy: + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 +``` + +⚠️ Careful yaml is indentation sensitive! + +## Next steps + +Mission accomplished, right? If everything went well, you should have a published website at this point! +Here are some next steps you could consider: + +### Use fsx file in your documentation + +Create documentation using [Literate Scripts](../literate.html). A typical flow here is that you load your locate project binary into a script and create examples using the latest code: + +```fsharp +#r "../src/Project1/bin/Debug/net6.0/Project1.dll" + +open Project1 + +// Actual consumption of your project! +let result = SomeType.SomeMethod("foo") +``` + +When using the `--strict` flag in `dotnet fsdocs build`, your documentation generation will fail if your script contains errors. +This is useful to ensure your documentation is always in sync with your latest public API! + +### Automatically update to newer versions of fsdocs-tool + +Using [Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates) you can easily receive new PR's with updates to your `dotnet` dependencies. + +Create a `github/dependabot.yml` file with: + +```yml +version: 2 +updates: + # Update to newer version of GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + + # Update to newer NuGet dependencies + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "daily" +``` + +This will automatically create a new PR when there is an update to the `fsdocs` tool. + +⚠️ P️lease be very careful, if you have followed along, we don't have any GitHub Actions right now that run against pull requests! +It is recommended to have an Action that builds your documentation against any incoming changes. +You typically want to lint code, run unit tests and perform other useful checks as well! + +Example Action, `.github/workflows/ci.yml`: +```yml +name: CI + +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET Core + uses: actions/setup-dotnet@v3 + - name: Restore tools + run: dotnet tool restore + - name: Build + run: dotnet build YourSolution.sln + - name: Documentation + run: dotnet fsdocs build +``` + +⚠️ Also never trust any update to `fsdocs` blindly, always check the [release notes](https://github.com/fsprojects/FSharp.Formatting/blob/main/RELEASE_NOTES.md) to see if there are any breaking changes.