====== Publishing mods on CurseForge, Modrinth & GitHub with MC-Publish ======
MC-Publish is a GitHub Action by Kir-Antipov that communicates with GitHub, CurseForge and Modrinth APIs to upload your mod files. This page only goes through the basics of the set-up and you should [[https://github.com/Kir-Antipov/mc-publish#publish-minecraft-mods---github-action|check out its Github documentation for further information]].
===== What are GitHub Actions? =====
[[https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions|Github Actions]] are essentially commands that get executed on GitHub servers. They are free to use as long as your GitHub repository is public and come with a limit, that should not hinder you, if it isn't.
In Software Development Github Actions and similar workflow automation systems are standard place and help tremendously with making deployments (such as releasing a new version of your mod) as seamless as possible.
If you dread the manual process of uploading your mod to multiple platforms, this is the solution.
===== Before we start =====
You should have already done the following:
- create a repository of your mod on GitHub
- upload a version of your mod to CurseForge and Modrinth and have it approved
===== Setup =====
If we want Github to do something for us, we need to tell their servers what exactly we want. To do that we need to add a ''.yml'' file in ''/.github/workflows''. You can think of this ''.yml'' file as the config file of your Github Action. It does not matter how it is named, you should however pick a relevant name. [[https://de.wikipedia.org/wiki/YAML|YAML]] is generally similar to JSON in concept, but has a very different syntax. Just like Python you don't use curly braces ''{}'' and instead only use indention to declare your structure.
The general structure of your ''.yml'' file should look like this:
name: Publish on GitHub, CurseForge & Modrinth #The name of your GitHub Action on github.com
on: [ pull_request, workflow_dispatch ] #When your GitHub Action will be executed ('pull_request' -> on every Merge(/Pull) Request; 'workflow_dispatch' -> allows manual execution through github.com
env: #Environment variables that can later be referenced using ${{ env.MINECRAFT_VERSION }}. These are useful for repeating information and allow for quick changes for new mod updates
MINECRAFT_VERSION: 1.19.2
JAVA_VERSION: 17
permissions:
contents: write
jobs: #The place where you actually tell the GitHub server what to do.
build: #To publish your mod you only need one 'job', here it is called 'build'.
runs-on: ubuntu-latest #'runs-on' specifies the operation system (linux).
steps: #Under 'steps' you will list all the individual commands, such as MC-Publish by Kir-Antipov.
...
I recommend to keep ''on: [ pull_request, workflow_dispatch ]'' and adapt your usage of git branches accordingly. This means developing every update on its own branch and only merging into main when its ready to be released. If this absolutely does not fit your needs you can [[https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows|check for different triggers]] or just use ''workflow_dispatch''. Remember that you dont want to accidently start your GitHub Action while setting up.
Basic environments variables should include:
* Minecraft version
* Java version
* Your mod version
* Your mod release name
* publishing tokens (will come later)
==== Publishing steps ====
The arguably most important part of your ''.yml'' file!
First we will look at the syntax of a step, prepare all prerequisite steps and then finally go over MC-Publish.
=== Syntax ===
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Example step
if: ${{ condition is met }}
uses: actions/common-action
with:
variable1: Some Value
variable2: Another Value
run: ls -a
- name: Another Example step
...
* ''name'' The name of the step, should accurrately describe the step.
* ''if'' A condition that needs to return true in order for the step to execute.
* ''uses'' Here you can specify additional GitHub Actions. You could program everything yourself, but where is the point in that if someone already did that for you? MC-Publish by Kir-Antipov is an example of that.
* ''with'' If you specified a GitHub Action with ''uses'' you can input predefined variables with your own values.
* ''run'' Execute a command on the command line.
=== Prerequisite steps ===
The following steps mirror the steps you needed to take before you could develop mods on your pc, just imagine you are a simple linux server and suddenly someone wants you to upload their minecraft mod. You wouldn't even know what Java is.
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check Environment Variables
run: env
- name: Checkout Repository
uses: actions/checkout@v3
with:
submodules: true
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: "temurin"
java-version: 17
- name: Make Gradle Wrapper Executable
if: ${{ runner.os != 'Windows' }}
run: chmod +x ./gradlew
- name: Build
run: ./gradlew clean build
...
While the steps above are necessary you dont need to understand them fully. If you are interested and want to fully understand them I recommend taking a beginner linux course.
During execution the 'Build' step will take by far the longest (~3min.), so dont worry if something goes wrong it will tell you.
=== MC-Publish ===
This section will by its nature not be complete, to get a full overview you can [[https://github.com/Kir-Antipov/mc-publish#publish-minecraft-mods---github-action|check the official GitHub Documentation of MC-Publish]].
jobs:
build:
runs-on: ubuntu-latest
steps:
...
- name: Publish (CurseForge/Modrinth/GitHub)
uses: Kir-Antipov/mc-publish@v3.2 #The specified MC-Publish GitHub Action in the version 3.2
with:
curseforge-id: 123456 #The id of your CurseForge project
curseforge-token: "${{env.CURSEFORGE_TOKEN}}"
modrinth-id: 1q2w3e4r #The id of your modrinth project
modrinth-token: "${{env.MODRINTH_TOKEN}}"
github-tag: "v${{env.VERSION}}"
github-token: "${{env.GITHUB_TOKEN}}"
name: "${{env.RELEASE_NAME}}"
version: "${{env.VERSION}}"
version-type: release
changelog-file: CHANGELOG.md #The file in which the changes of your new update are specified (the path starts at your project root)
loaders: fabric
game-versions: "${{env.MINECRAFT_VERSION}}"
java: "${{env.JAVA_VERSION}}"
''CURSEFORGE_TOKEN'', ''MODRINTH_TOKEN'' or ''GITHUB_TOKEN'' are essentially passwords that are used to authenticate you as a person, that means these are specific to your account and **not** to your mod. This makes sure that only you can push updates through the API. When uploading normally you authenticate yourself when you log in. Where do you find these authentication tokens? It's different for every platform:
**//GitHub//** Settings > Developer Settings > Personal access tokens > Tokens (classic) => press "Generate new token" and choose classic => select the 'repo' scope (write a descriptive note, 90 days expiration is recommended, you will need to generate a new token afterwards) => press "Generate token"
**//Modrinth//** Settings => Authorization token
**//CurseForge//** Settings > My API Tokens => choose a descriptive name and press "Generate Token"
It is **strongly recommended** that you save the authentication tokens somewhere safe, e.g. a password manager. **GitHub //won't// let you access your token after you have generated it!**
Now that you have all the tokens you need, you have to make them accessible to your GitHub Action. Go to the settings page of your mod repository on github.com and navigate to Secrets > Actions. Add all your authentication tokens as secrets. You will need to reference the name you give them here in your ''.yml'' file. A secret named ''PUBLISH_CURSEFORGE_TOKEN'' can be referenced using
${{ secrets.PUBLISH_CURSEFORGE_TOKEN }}
==== Full .yml example ====
name: Publish on GitHub, CurseForge & Modrinth
on: [ pull_request, workflow_dispatch ]
env:
MINECRAFT_VERSION: 1.19.2
JAVA_VERSION: 17
VERSION: 1.1.0+1.19.2
RELEASE_NAME: Example Mod 1.1.0 for Minecraft 1.19.2
MODRINTH_TOKEN: ${{ secrets.PUBLISH_MODRINTH_TOKEN }}
CURSEFORGE_TOKEN: ${{ secrets.PUBLISH_CURSEFORGE_TOKEN }}
GITHUB_TOKEN: ${{ secrets.PUBLISH_GITHUB_TOKEN }}
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check Environment Variables
run: env
- name: Checkout Repository
uses: actions/checkout@v3
with:
submodules: true
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: "temurin"
java-version: 17
- name: Make Gradle Wrapper Executable
if: ${{ runner.os != 'Windows' }}
run: chmod +x ./gradlew
- name: Build
run: ./gradlew clean build
- name: Publish (CurseForge/Modrinth/GitHub)
uses: Kir-Antipov/mc-publish@v3.2
with:
curseforge-id: 123456
curseforge-token: "${{env.CURSEFORGE_TOKEN}}"
modrinth-id: 1q2w3e4r
modrinth-token: "${{env.MODRINTH_TOKEN}}"
github-tag: "v${{env.VERSION}}"
github-token: "${{env.GITHUB_TOKEN}}"
name: "${{env.RELEASE_NAME}}"
version: "${{env.VERSION}}"
version-type: release
changelog-file: CHANGELOG.md
loaders: fabric
game-versions: "${{env.MINECRAFT_VERSION}}"
java: "${{env.JAVA_VERSION}}"
===== Setup Complete =====
To recap, here is what you should have by now:
* Newly generated authentication tokens for every platform
* Authentication tokens stored as secrets in your GitHub repository
* a ''.yml'' file in ''/.github/workflows'' pushed to your github repository
* a empty ''CHANGELOG.md'' file in your project root
If you have all these you are finished! You can now use your newly created GitHub Action to deploy updates for your mod!
===== Additional tips =====
Here is a list of useful resources that didn't fit into the general tutorial.
==== Update Checklist ====
When updating your mod you now have a few places you need to look at.
* update the version number
* in ''src/fabric.mod.json'' under ''"version": "1.1.0+1.19.2"''
* in ''gradle.properties'' (typically) under ''mod_version = 1.1.0+1.19.2''
* in ''.github/workflows/publish.yml'' under ''VERSION: 1.1.0+1.19.2'' and ''RELEASE_NAME: Example Mod 1.1.0 for Minecraft 1.19.2''
* update the changelog in ''CHANGELOG.md''
* (if you use the recommended workflow) Merge the update branch into the current default branch
==== Handling dependencies ====
[[https://github.com/Kir-Antipov/mc-publish#dependencies|Check out the official documentation]]. I recommend using the ''fabric.mod.json'' approach.
==== Errors when uploading to Modrinth ====
Since Modrinth updated its API some people have problems uploading through the API. If that happens to you, try separating the Modrinth portion from GitHub and CurseForge. You can do this easily by copying the MC-Publish step and trimming out the now unnecessary input in ''with''. You should now have two separate steps.
Change the version in the step that publishes to modrinth to 2.1 -> ''uses: Kir-Antipov/mc-publish@v2.1''