Table of Contents
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 check out its Github documentation for further information.
What are 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. 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 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 withuses
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 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) undermod_version = 1.1.0+1.19.2
- in
.github/workflows/publish.yml
underVERSION: 1.1.0+1.19.2
andRELEASE_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
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