Skip to content

Commit

Permalink
Add frontmatter parser for markdown content type
Browse files Browse the repository at this point in the history
Should the action read and delete frontmatter in a markdown file. Frontmatter should start with --- and end with ---. Should be on the top of the page. When parsing frontmatter, only markdown is supported and settings will be overwritten if specified in the frontmatter.

Signed-off-by: Brend Smits <[email protected]>
  • Loading branch information
Brend-Smits committed Nov 2, 2021
1 parent 74252d7 commit db15da5
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 6 deletions.
3 changes: 2 additions & 1 deletion Action/.env-example
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ License=all-rights-reserved
PublicationId=123456789
PublicationName=Philips Tech Blog
NotifyFollowers=true
File=
File=
ParseFrontmatter=false
2 changes: 2 additions & 0 deletions Action/PostMediumGitHubAction.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="DotNetEnv" Version="2.2.0" />
<PackageReference Include="Markdig" Version="0.26.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.11.1" />
<PackageReference Include="YamlDotNet" Version="11.2.1" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion Action/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"profiles": {
"PostMediumGitHubAction2": {
"PostMediumGitHubAction": {
"commandName": "Project"
},
"Docker": {
Expand Down
41 changes: 41 additions & 0 deletions Action/Services/ConfigureService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using CommandLine;
Expand All @@ -7,6 +8,9 @@ namespace PostMediumGitHubAction.Services
{
internal class ConfigureService
{
public ConfigureService()
{
}
public ConfigureService(string[] args)
{
ConfigureApplication(args);
Expand All @@ -31,6 +35,7 @@ private void ConfigureApplication(string[] args)
Program.Settings.PublicationName =
Environment.GetEnvironmentVariable(nameof(Program.Settings.PublicationName));
Program.Settings.PublishStatus = Environment.GetEnvironmentVariable(nameof(Program.Settings.PublishStatus));
Program.Settings.ParseFrontmatter = Convert.ToBoolean(Environment.GetEnvironmentVariable(nameof(Program.Settings.ParseFrontmatter)));
Program.Settings.Tags = Environment.GetEnvironmentVariable(nameof(Program.Settings.Tags))?.Split(',');
Program.Settings.Title = Environment.GetEnvironmentVariable(nameof(Program.Settings.Title));

Expand All @@ -53,6 +58,42 @@ private void ConfigureApplication(string[] args)
Program.Settings.ContentFormat = Program.Settings.ContentFormat?.ToLower();
}

/// <summary>
/// Override Program Settings with values from parameter if they are not null.
/// </summary>
/// <param name="settingsToReplace">Settings to replace Program settings with</param>
public void OverrideSettings(Settings settingsToReplace)
{
if (settingsToReplace.CanonicalUrl != null)
{
Program.Settings.CanonicalUrl = settingsToReplace.CanonicalUrl;
}

if (settingsToReplace.ContentFormat != null)
{
Program.Settings.ContentFormat = settingsToReplace.ContentFormat;
}

if (settingsToReplace.Tags.Any())
{
Program.Settings.Tags = settingsToReplace.Tags;
}

if (settingsToReplace.License != null)
{
Program.Settings.License = settingsToReplace.License;
}

if (settingsToReplace.PublishStatus != null)
{
Program.Settings.PublishStatus = settingsToReplace.PublishStatus;
}

if (settingsToReplace.Title != null)
{
Program.Settings.Title = settingsToReplace.Title;
}
}
/// <summary>
/// Checks if settings are filled in correctly.
/// </summary>
Expand Down
54 changes: 53 additions & 1 deletion Action/Services/MediumService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Markdig;
using Markdig.Extensions.Yaml;
using Markdig.Renderers;
using Markdig.Syntax;
using PostMediumGitHubAction.Domain;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace PostMediumGitHubAction.Services
{
public class MediumService
{
private ConfigureService _configureService = new ConfigureService();
public async Task SubmitNewContentAsync()
{
User user = await GetCurrentMediumUserAsync();
Expand All @@ -20,11 +27,56 @@ public async Task SubmitNewContentAsync()

if (!string.IsNullOrEmpty(Program.Settings.File))
Program.Settings.Content = await ReadFileFromPath(Program.Settings.File);
if (Program.Settings.ContentFormat == "markdown" && Program.Settings.ParseFrontmatter)
{
await ParseFrontmatter(Program.Settings.Content);
}

MediumCreatedPost post = await CreateNewPostUnderPublicationAsync(pub.Id);
SetWorkflowOutputs(post);
}

/// <summary>
/// Parse markdown content and look for frontmatter.
/// Convert the markdown into HTML to remove the frontmatter.
/// </summary>
/// <param name="content">Content in markdown</param>
/// <returns></returns>
private async Task ParseFrontmatter(string content)
{
MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
.UseYamlFrontMatter()
.Build();

StringWriter writer = new StringWriter();
HtmlRenderer renderer = new HtmlRenderer(writer);
pipeline.Setup(renderer);

MarkdownDocument document = Markdown.Parse(content, pipeline);

// extract the front matter from markdown document
YamlFrontMatterBlock yamlBlock = document.Descendants<YamlFrontMatterBlock>().FirstOrDefault();

if (yamlBlock != null)
{
string yaml = yamlBlock.Lines.ToString();

// deserialize the yaml block into a custom type
IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(PascalCaseNamingConvention.Instance)
.Build();

Settings metadata = deserializer.Deserialize<Settings>(yaml);
_configureService.OverrideSettings(metadata);
// finally we can render the markdown content as html if necessary
renderer.Render(document);
await writer.FlushAsync();
string html = writer.ToString();
Program.Settings.Content = html;
Program.Settings.ContentFormat = "html";
}
}

/// <summary>
/// Retrieves current authenticated user
/// </summary>
Expand Down Expand Up @@ -79,7 +131,7 @@ public async Task<MediumCreatedPost> CreateNewPostUnderPublicationAsync(string p
Content = Program.Settings.Content,
ContentFormat = Program.Settings.ContentFormat,
PublishStatus = Program.Settings.PublishStatus,
Tags = (string[])Program.Settings.Tags,
Tags = Program.Settings.Tags as string[],
Title = Program.Settings.Title
};
HttpResponseMessage response = await Program.Client.PostAsync($"publications/{publicationId}/posts",
Expand Down
4 changes: 4 additions & 0 deletions Action/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,9 @@ public class Settings
HelpText =
"The token that should be used to authenticate in the API. Token can be retrieved at https://medium.com/me/settings under \"Integration Token\"")]
public string IntegrationToken { get; set; }

[Option('m', "parse-frontmatter", Required = false,
HelpText = "Should the action read and delete frontmatter in a markdown file. Frontmatter should start with --- and end with ---. Should be on the top of the page. When parsing frontmatter, only markdown is supported and settings will be overwritten if specified in the frontmatter.")]
public bool ParseFrontmatter { get; set; } = false;
}
}
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@
<p align="right">(<a href="#top">back to top</a>)</p>

## State
> Functional, but work in progress. Use at your own risk.
> Functional
## Usage

The easiest way to use this action is to add the following into your workflow file. Additional configuration might be necessary to fit your usecase.

1. Add the following part in your workflow file:

```yaml
```
jobs:
post-to-medium:
name: Post to Medium
runs-on: ubuntu-latest
steps:
- name: Create Medium Post
uses: philips-software/post-to-medium-action@v0.2
uses: philips-software/post-to-medium-action@v0.3
with:
integration_token: "${{ secrets.INTEGRATION_TOKEN }}"
content: "content here"
Expand Down Expand Up @@ -69,6 +69,7 @@ The easiest way to use this action is to add the following into your workflow fi
| canonical_url | The canonical URL of the post. If canonicalUrl was not specified in the creation of the post, this field will not be present. | `false` | |
| tags | The post’s tags. Provide a comma separated string without spaces. | `true` | |
| title | The post's title. | `true` | |
| parse_frontmatter | Should the action read and delete frontmatter in a markdown file. Frontmatter should start with --- and end with ---. Should be on the top of the page. When parsing frontmatter, only markdown is supported and settings will be overwritten if specified in the frontmatter. | `true` | false |


## Outputs
Expand Down
6 changes: 6 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ inputs:
description: "The post's title."
required: true
default: ""
parse_frontmatter:
description: "Should the action read and delete frontmatter in a markdown file. Frontmatter should start with --- and end with ---. Should be on the top of the page. When parsing frontmatter, only markdown is supported and settings will be overwritten if specified in the frontmatter."
required: false
default: "false"

outputs:
id:
Expand Down Expand Up @@ -98,6 +102,8 @@ runs:
- ${{ inputs.content }}
- '--file'
- ${{ inputs.file }}
- '--parse-frontmatter'
- ${{ inputs.parse_frontmatter }}


branding:
Expand Down

0 comments on commit db15da5

Please sign in to comment.