Added many, many more actions.

This commit is contained in:
2025-06-24 15:24:16 -07:00
parent 62fbe4dead
commit 57ef232d2b
108 changed files with 4212 additions and 7 deletions

7
aws/aws-cli/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
# Container image that runs your code
FROM amazon/aws-cli:2.9.15
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

28
aws/aws-cli/action.yaml Normal file
View File

@@ -0,0 +1,28 @@
name: aws-cli
description: "Run aws cli commands."
inputs:
args:
description: "Arguments to pass into the aws cli."
required: true
accessKey:
description: "AWS access key."
required: true
secretKey:
description: "AWS secret key."
required: true
region:
description: "AWS region."
required: true
default: us-gov-west-1
outputs:
console:
description: "The console output of the aws command."
runs:
using: docker
image: Dockerfile
env:
AWS_ACCESS_KEY_ID: ${{ inputs.accessKey }}
AWS_SECRET_ACCESS_KEY: ${{ inputs.secretKey }}
AWS_DEFAULT_REGION: ${{ inputs.region }}
args:
- ${{ inputs.args }}

16
aws/aws-cli/entrypoint.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
ARGS="$@"
OUTPUT=$(bash -c "aws $ARGS")
RESULT=$?
echo "$OUTPUT"
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
exit $RESULT

29
aws/aws-s3-cp/action.yaml Normal file
View File

@@ -0,0 +1,29 @@
name: aws-s3-cp
description: "Copy files to or from s3."
inputs:
target:
description: "Target file."
required: true
dest:
description: "Destination file."
required: true
accessKey:
description: "AWS access key."
required: true
secretKey:
description: "AWS secret key."
required: true
region:
description: "AWS region."
required: true
default: us-gov-west-1
runs:
using: "composite"
steps:
- name: "Copy files to/from S3."
uses: act/common/aws/aws-cli@master
with:
args: s3 cp "${{ inputs.target }}" "${{ inputs.dest }}" --recursive
accessKey: ${{ inputs.accessKey }}
secretKey: ${{ inputs.secretKey }}
region: ${{ inputs.region }}

View File

@@ -4,4 +4,4 @@ FROM busybox:1.36.0
COPY entrypoint.sh /entrypoint.sh COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"] ENTRYPOINT ["/entrypoint.sh"]

11
distros/debian/Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
# Container image that runs your code
FROM debian:12.0
RUN apt update && apt upgrade -y
RUN apt install -y \
gridsite-clients
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,14 @@
name: debian
description: "Run Debian commands."
inputs:
args:
description: "Shell arguments to pass into Debian."
required: true
outputs:
console:
description: "The console output of the command."
runs:
using: docker
image: Dockerfile
args:
- "${{ inputs.args }}"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
ARGS="$@"
OUTPUT=$(bash -c "$ARGS")
RESULT=$?
echo "$OUTPUT"
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
exit $RESULT

View File

@@ -0,0 +1,19 @@
# Container image that runs your code
FROM rockylinux:9.1
RUN dnf install -y \
rpm-sign \
unzip \
pinentry \
wget \
uuid \
gettext
COPY setup_gpg.sh /setup_gpg.sh
RUN chmod +x /setup_gpg.sh
RUN /setup_gpg.sh
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

View File

@@ -0,0 +1,14 @@
name: rockylinux
description: "Run rockylinux commands."
inputs:
args:
description: "Shell arguments to pass into Rocky Linux."
required: true
outputs:
console:
description: "The console output of the command."
runs:
using: docker
image: Dockerfile
args:
- "${{ inputs.args }}"

View File

@@ -0,0 +1,16 @@
#!/bin/sh
ARGS="$@"
OUTPUT=$(bash -c "$ARGS")
RESULT=$?
echo "$OUTPUT"
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
exit $RESULT

View File

@@ -0,0 +1,29 @@
#!/bin/bash
#Importing gpg key via cli
#https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors
GPG_CONF="$HOME/.gnupg/gpg.conf"
GPG_AGENT_CONF="$HOME/.gnupg/gpg-agent.conf"
function create_file
{
FILE_PATH="$1"
CONTENTS="$2"
DIR=$(dirname "$FILE_PATH")
mkdir -p "$DIR"
chmod 700 "$DIR"
echo "$CONTENTS" > "$FILE_PATH"
}
create_file "$GPG_CONF" "$(cat <<EOF
use-agent
pinentry-mode loopback
EOF
)"
create_file "$GPG_AGENT_CONF" "$(cat <<EOF
allow-loopback-pinentry
EOF
)"
echo "RELOADAGENT" | gpg-connect-agent

View File

@@ -0,0 +1,38 @@
name: dotnet-nugetforunity-restore
description: "Restore NugetForUnity packages."
inputs:
projectPath:
description: "Path to the Unity project."
required: true
default: "."
restoreMode:
description: "Whether or not to resture NuGetForUnity packages. Options: true, false, auto"
required: true
default: auto
runs:
using: "composite"
steps:
- name: "Determine if NuGet packages need restored."
id: nuget
run: |
NUGET="${{ inputs.restoreMode }}"
if [ "$NUGET" == "auto" ]; then
if [ -f "${{ inputs.projectPath }}/Assets/NuGet.config" ]; then
NUGET=true
else
NUGET=false
fi
fi
echo "restoreMode=$NUGET" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Restore NuGet packages."
if: ${{ steps.nuget.outputs.restoreMode == 'true' }}
uses: act/common/dotnet/dotnet@master
with:
program: nugetforunity
command: restore "${{ inputs.projectPath }}"
- name: "Own artifacts."
if: ${{ steps.nuget.outputs.restoreMode == 'true' }}
uses: act/common/utils/chown@master
with:
file: ${{ inputs.projectPath }}/Assets/Packages

View File

@@ -0,0 +1,24 @@
name: dotnet-push
description: "Push a nuget package with dotnet."
inputs:
nupkg:
description: "Path to the .nupkg to push."
required: true
url:
description: "URL of the nuget repository to push to."
required: true
default: ${{ github.server_url }}/_registry/nuget/${{ github.repository_owner }}/index.json
apiKey:
description: "ApiKey of the nuget repository to push to."
required: true
default: ${{ github.token }}
options:
description: "Additional options when pushing the .nupkg."
required: false
runs:
using: "composite"
steps:
- name: "Push the NuGet package."
uses: act/common/dotnet/dotnet@master
with:
command: nuget push ${{ inputs.nupkg }} -s ${{ inputs.url }} -k ${{ inputs.apiKey }} ${{ inputs.options }}

14
dotnet/dotnet/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
ARG VERSION=7.0
FROM mcr.microsoft.com/dotnet/sdk:$VERSION
RUN apt update
RUN apt install curl -y
# Add tools to Path.
RUN echo 'export PATH="$PATH:$HOME/.dotnet/tools/"' | tee -a "$HOME/.bashrc" > /dev/null
# Install NugetForUnity tool: https://github.com/GlitchEnzo/NuGetForUnity
RUN dotnet tool install --global NuGetForUnity.Cli
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

21
dotnet/dotnet/action.yaml Normal file
View File

@@ -0,0 +1,21 @@
name: dotnet
description: "Run a dotnet command."
inputs:
command:
description: "Dotnet command to run."
required: false
program:
description: "Program to run instead of dotnet. Default: dotnet"
required: false
default: "dotnet"
catchErrors:
description: "Whether or not errors should be handled."
required: false
runs:
env:
PROGRAM: ${{ inputs.program }}
CATCH_ERRORS: ${{ inputs.catchErrors }}
using: 'docker'
image: 'Dockerfile'
args:
- ${{ inputs.command }}

View File

@@ -0,0 +1,25 @@
#!/bin/bash
COMMAND="$@"
set -o pipefail
# Add root tools to Path.
export PATH="$PATH:/root/.dotnet/tools/"
PROGRAM=${PROGRAM:-"dotnet"}
exec 5>&1
OUTPUT=$(bash -c "$PROGRAM $COMMAND" | tee /dev/fd/5)
RESULT=$?
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
echo "exitCode=$RESULT" >> "$GITHUB_OUTPUT"
if [[ "$CATCH_ERRORS" != "true" ]]; then
exit $RESULT
fi

View File

@@ -0,0 +1,89 @@
name: gitea-get-next-branched-version
description: "Get the next version of a Gitea package based on the current branch status."
inputs:
name:
description: "The name of the package."
required: true
defaultVersion:
description: "Default version to use."
required: true
default: 1.0.0
url:
description: "Url of the Gitea server instance."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token for Gitea."
required: true
default: ${{ github.token }}
type:
description: "The type of package to search for."
required: false
default: ""
page:
description: "The page number of results to return."
required: false
default: ""
limit:
description: "The page size of results."
required: false
default: ""
prerelease:
description: "Query prerelease packages. Values: true, false."
required: false
default: "${{ github.event_name == 'pull_request' }}"
outputs:
latestVersion:
description: "The current latest version for the .nupkg."
value: ${{ steps.version.outputs.version || steps.packageFallback.outputs.version }}
nextVersion:
description: "The next version for the .nupkg file."
value: ${{ steps.version.outputs.nextVersion }}
runs:
using: "composite"
steps:
- name: "Get the base version for the package."
uses: act/common/utils/version-increment-branch@master
id: base
with:
version: ${{ inputs.defaultVersion }}
- run: echo "${{ steps.base.outputs.majorMinorPatchVersion }}"
- name: "Get versions."
id: package
uses: act/common/gitea/gitea-query-package-versions-latest@master
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
type: ${{ inputs.type }}
page: ${{ inputs.page }}
limit: ${{ inputs.limit }}
name: ${{ inputs.name }}
filter: ^${{ steps.base.outputs.baseVersion }}
prerelease: ${{ inputs.prerelease }}
- name: "If no version is found, get the latest version for the package if we didn't already look for it."
uses: act/common/gitea/gitea-query-package-versions-latest@master
id: packageFallback
if: ${{ steps.version.outputs.version == '' && inputs.prerelease != 'false' }}
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
type: ${{ inputs.type }}
page: ${{ inputs.page }}
limit: ${{ inputs.limit }}
name: ${{ inputs.name }}
filter: ^${{ steps.base.outputs.majorMinorPatchVersion }}
prerelease: false
- run: echo "${{ steps.version.outputs.version == '' }}" AND "${{ inputs.prerelease != 'false' }}"
- if: ${{ steps.version.outputs.version == '' && inputs.prerelease != 'false' }}
run: echo "${{ steps.packageFallback.outputs.version }}"
- name: "Get the next version for the package."
uses: act/common/utils/version-increment-branch@master
id: version
with:
version: ${{ steps.package.outputs.version || steps.packageFallback.outputs.version || inputs.defaultVersion }}

View File

@@ -0,0 +1,71 @@
name: gitea-query-package-versions-latest
description: "Get the latest version of a package."
inputs:
url:
description: "Url of the Gitea server instance."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token for Gitea."
required: true
default: ${{ github.token }}
type:
description: "The type of package to search for."
required: false
default: ""
page:
description: "The page number of results to return."
required: false
default: ""
limit:
description: "The page size of results."
required: false
default: ""
prerelease:
description: "Whether to include prerelease packages. Values: true, false."
required: false
default: "false"
name:
description: "Name of a specific package."
required: true
filter:
description: "String to filter by."
required: false
filterIsExpression:
description: "Is the first filter a Regular Expression? Values: true, false."
required: false
default: "false"
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
version:
description: "The latest version of the specified package."
value: ${{ steps.parse.outputs.version }}
runs:
using: "composite"
steps:
- name: "Get versions."
id: versions
uses: act/common/gitea/gitea-query-package-versions@master
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
type: ${{ inputs.type }}
page: ${{ inputs.page }}
limit: ${{ inputs.limit }}
name: ${{ inputs.name }}
additionalArgs: ${{ inputs.additionalArgs }}
- name: "Parse query result."
id: parse
uses: act/common/utils/get-latest-version@master
with:
versions: ${{ steps.versions.outputs.versions }}
filter: ${{ inputs.filter }}
filterIsExpression: ${{ inputs.filterIsExpression }}
stripPrerelease: ${{ inputs.prerelease == 'false' }}

View File

@@ -0,0 +1,58 @@
name: github-query-nuget-versions
description: "Change the language format of a file."
inputs:
url:
description: "Url of the GitHub server repository."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token to for GitHub."
required: true
default: ${{ github.token }}
type:
description: "The type of package to search for."
required: false
default: ""
page:
description: "The page number of results to return."
required: false
default: ""
limit:
description: "The page size of results."
required: false
default: ""
name:
description: "Name of a specific package."
required: true
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
versions:
description: "The versions of the specified package."
value: ${{ steps.parse.outputs.result }}
runs:
using: "composite"
steps:
- name: "Build and run query."
id: query
uses: act/common/gitea/gitea-query-packages@master
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
type: ${{ inputs.type }}
page: ${{ inputs.page }}
limit: ${{ inputs.limit }}
name: ${{ inputs.name }}
additionalArgs: ${{ inputs.additionalArgs }}
- name: "Parse query result."
id: parse
uses: act/common/yq/yq-expression@master
with:
expression: .[] | select(.name == "${{ inputs.name }}").version
input: ${{ steps.query.outputs.query }}

View File

@@ -0,0 +1,73 @@
name: gitea-query-packages
description: "Change the language format of a file."
inputs:
url:
description: "Url of the Gitea server repository."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token to for Gitea."
required: true
default: ${{ github.token }}
type:
description: "The type of package to search for."
required: false
default: ""
page:
description: "The page number of results to return."
required: false
default: ""
limit:
description: "The page size of results."
required: false
default: ""
name:
description: "Name of a specific package."
required: false
default: ""
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
query:
description: "The query result."
value: ${{ steps.query.outputs.query }}
runs:
using: "composite"
steps:
- name: "Build route."
id: route
run: |
ROUTE="/api/v1/packages/${{ inputs.organization }}?"
NAME="${{ inputs.name }}"
TYPE="${{ inputs.type }}"
PAGE="${{ inputs.page }}"
LIMIT="${{ inputs.limit }}"
if [[ -n "$NAME" ]]; then
ROUTE="${ROUTE}q=$NAME&"
fi
if [[ -n "$TYPE" ]]; then
ROUTE="${ROUTE}type=$TYPE&"
fi
if [[ -n "$PAGE" ]]; then
ROUTE="${ROUTE}page=$PAGE&"
fi
if [[ -n "$LIMIT" ]]; then
ROUTE="${ROUTE}limit=$LIMIT&"
fi
echo "route=$ROUTE" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Build and run query."
id: query
uses: act/common/github/github-query@master
with:
url: ${{ inputs.url }}
route: ${{ steps.route.outputs.route }}
apiToken: ${{ inputs.apiToken }}
additionalArgs: ${{ inputs.additionalArgs }}

View File

@@ -0,0 +1,69 @@
name: gitea-upload-generic-package
description: "Upload a generic package to Gitea."
inputs:
url:
description: "Url of the Gitea server repository."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to upload the package to."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token to for Gitea."
required: true
default: ${{ github.token }}
version:
description: "The version of package to upload."
required: false
default: ""
name:
description: "Name of the package."
required: false
default: ""
file:
description: "Path of the file to upload."
required: false
default: ""
filename:
description: "Name to upload the file as. Defaults to the basename of the file."
required: false
default: ""
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
query:
description: "The query result."
value: ${{ steps.query.outputs.query }}
runs:
using: "composite"
steps:
- name: "Get filename."
id: file
run: |
FILE="${{ inputs.filename }}"
if [[ -z "$FILE" ]]; then
FILE="${{ inputs.file }}"
fi
FILE=$(basename "$FILE")
echo "file=$FILE" >> "$GITHUB_OUTPUT"
shell: bash
- uses: act/common/utils/urlencode@master
id: url
with:
input: ${{ steps.file.outputs.file }}
- name: "Build route."
id: route
run: |
ROUTE="/api/packages/${{ inputs.organization }}/generic/${{ inputs.name }}/${{ inputs.version }}/${{ steps.url.outputs.result }}"
echo "route=$ROUTE" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Build and run query."
id: query
uses: act/common/github/github-query@master
with:
url: ${{ inputs.url }}
route: ${{ steps.route.outputs.route }}
apiToken: ${{ inputs.apiToken }}
additionalArgs: --upload-file "${{ inputs.file }}" ${{ inputs.additionalArgs }}

View File

@@ -0,0 +1,56 @@
name: github-query-nuget-versions-latest
description: "Get the latest version of a NuGet package."
inputs:
url:
description: "Url of the GitHub server instance."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token for GitHub."
required: true
default: ${{ github.token }}
prerelease:
description: "Show prerelease packages. Values: true, false."
required: false
default: "false"
name:
description: "Name of a specific package."
required: true
filter:
description: "String to filter by."
required: false
filterIsExpression:
description: "Is the first filter a Regular Expression? Values: true, false."
required: false
default: "false"
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
version:
description: "The latest version of the specified package."
value: ${{ steps.parse.outputs.version }}
runs:
using: "composite"
steps:
- name: "Get versions."
id: versions
uses: act/common/github/github-query-nuget-versions@master
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
prerelease: ${{ inputs.prerelease }}
name: ${{ inputs.name }}
additionalArgs: ${{ inputs.additionalArgs }}
- name: "Parse query result."
id: parse
uses: act/common/utils/get-latest-version@master
with:
versions: ${{ steps.versions.outputs.versions }}
filter: ${{ inputs.filter }}
filterIsExpression: ${{ inputs.filterIsExpression }}

View File

@@ -0,0 +1,48 @@
name: github-query-nuget-versions
description: "Get the versions of a NuGet package."
inputs:
url:
description: "Url of the GitHub server repository."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token to for GitHub."
required: true
default: ${{ github.token }}
prerelease:
description: "Show prerelease packages. Values: true, false."
required: false
default: "false"
name:
description: "Name of a specific package."
required: true
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
versions:
description: "The versions of the specified package."
value: ${{ steps.parse.outputs.result }}
runs:
using: "composite"
steps:
- name: "Build and run query."
id: query
uses: act/common/github/github-query-nuget@master
with:
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
prerelease: ${{ inputs.prerelease }}
name: ${{ inputs.name }}
additionalArgs: ${{ inputs.additionalArgs }}
- name: "Parse query result."
id: parse
uses: act/common/yq/yq-expression@master
with:
expression: .data[] | select(.id == "${{ inputs.name }}").versions[].version
input: ${{ steps.query.outputs.query }}

View File

@@ -0,0 +1,56 @@
name: github-query-nuget
description: "Make a query to the GitHub NuGet api."
inputs:
url:
description: "Url of the GitHub server repository."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token to for GitHub."
required: true
default: ${{ github.token }}
prerelease:
description: "Show prerelease packages. Values: true, false."
required: false
default: "false"
name:
description: "Name of a specific package."
required: false
default: ""
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
query:
description: "The query result."
value: ${{ steps.query.outputs.query }}
runs:
using: "composite"
steps:
- name: "Build route."
id: route
run: |
ROUTE="/_registry/nuget/${{ inputs.organization }}/query?"
NAME="${{ inputs.name }}"
PRERELEASE="${{ inputs.prerelease }}"
if [[ "$PRERELEASE" == "true" ]]; then
ROUTE="${ROUTE}prerelease=true&"
fi
if [[ -n "$NAME" ]]; then
ROUTE="${ROUTE}q=$NAME"
fi
echo "route=$ROUTE" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Build and run query."
id: query
uses: act/common/github/github-query@master
with:
url: ${{ inputs.url }}
route: ${{ steps.route.outputs.route }}
apiToken: ${{ inputs.apiToken }}
additionalArgs: ${{ inputs.additionalArgs }}

View File

@@ -0,0 +1,54 @@
name: github-query
description: "Make a query to GitHub."
inputs:
url:
description: "Url of the GitHub server repository."
required: true
default: ${{ github.server_url }}
route:
description: "Route of the api to call."
required: false
default: ""
apiToken:
description: "Api Token to for GitHub."
required: false
default: ${{ github.token }}
additionalArgs:
description: "Additional arguments to pass into curl."
required: false
outputs:
query:
description: "The query result."
value: ${{ steps.query.outputs.console }}
runs:
using: "composite"
steps:
- name: "Build and run query."
id: query
run: |
URL_ROOT="${{ inputs.url }}"
# Remove any trailing slash from the url root
URL_ROOT=${URL_ROOT%/}
# Remove any leading slash from the route
ROUTE="${{ inputs.route }}"
ROUTE=${ROUTE#/}
FULL_URL="$URL_ROOT/$ROUTE"
QUERY="curl -sL \"$FULL_URL\" ${{ inputs.additionalArgs }}"
TOKEN="${{ inputs.apiToken }}"
if [[ -n "$TOKEN" ]]; then
QUERY="$QUERY -H \"Authorization: token $TOKEN\""
fi
OUTPUT=$(eval "$QUERY")
RESULT=$?
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
exit $RESULT
shell: bash

View File

@@ -0,0 +1,84 @@
name: mc-find-tags
description: "Find files in s3."
inputs:
accessKey:
description: "S3 access key."
required: true
secretKey:
description: "S3 secret key."
required: true
alias:
description: "S3 alias."
required: true
url:
description: "S3 url."
required: true
default: https://s3-us-gov-west-1.amazonaws.com
path:
description: "The path to search for."
required: true
name:
description: "The name pattern to search for."
required: true
default: ""
tags:
description: "The tags/version to search for."
required: true
default: ""
additionalArgs:
description: "Additional arguments."
required: false
outputs:
files:
description: "The path of the found file."
value: ${{ steps.output.outputs.files }}
console:
description: "The console output of the command."
value: ${{ steps.output.outputs.console }}
success:
description: "Whether files were found."
value: ${{ steps.output.outputs.success }}
runs:
using: "composite"
steps:
- name: "Build command."
id: command
run: |
COMMAND="find \"${{ inputs.path }}\" ${{ inputs.additionalArgs }}"
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
if [[ -n "${{ inputs.name }}" ]]; then
COMMAND="$COMMAND --name \"${{ inputs.name }}\""
fi
if [[ -n "${{ inputs.tags }}" ]]; then
COMMAND="$COMMAND --exec \"mc tag list {}\""
fi
shell: bash
- name: "Find file in S3."
id: find
uses: act/common/minio/mc@master
with:
alias: ${{ inputs.alias }}
command: ${{ steps.command.outputs.command }}
accessKey: ${{ inputs.accessKey }}
secretKey: ${{ inputs.secretKey }}
url: ${{ inputs.url }}
catchErrors: true
- name: "Set output."
id: output
run: |
RESULT="${{ steps.find.outputs.exitCode }}"
if [[ "$RESULT" != "0" ]]; then
SUCCESS="false"
else
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "${{ steps.find.outputs.console }}" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
SUCCESS="true"
fi
echo "success=$SUCCESS" >> "$GITHUB_OUTPUT"
shell: bash

View File

@@ -0,0 +1,37 @@
MINIO_URL="$1"
MINIO_ALIAS="$2"
OUTPUT=$(cat <<EOF
$3
EOF
)
IDS=""
URLS=""
TAGS=""
while read -r line; do
if [[ $line == "Name"* ]]; then
# Collapes the spaces.
COLLAPSED=$(echo "$line" | tr -s " ")
# Split the string by spaces.
URL=$(echo "$COLLAPSED" | cut -d " " -f 3)
ID=$(echo "$COLLAPSED" | cut -d " " -f 4 | tr -d "()")
URLS+="$URL "
IDS+="$ID "
TAGS="${TAGS%?} "
else
VARNAME=$(echo "$line" | cut -d ":" -f 1 | xargs)
VARVAL=$(echo "$line" | cut -d ":" -f 2 | xargs)
TAGS+="$VARNAME=$VARVAL&"
fi
done <<< "$OUTPUT"
# Remove last amperstand.
TAGS=$(echo "${TAGS%?}")
# Remove first space.
TAGS=$(echo "${TAGS/ /}")
URLS=$(echo "$URLS" | xargs)
ALIASED_URLS=$(echo "$URLS" | sed -e "s|^$MINIO_URL|$MINIO_ALIAS|g" | xargs)
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
echo "urls=$URLS" >> "$GITHUB_OUTPUT"
echo "aliasedUrls=$ALIASED_URLS" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,49 @@
name: ikdasm-files
description: "Run ikdasm to disassemble .NET assemblies in a folder."
inputs:
directory:
description: "Directory to search."
required: true
default: '.'
pattern:
description: "Pattern of files to search for."
required: true
default: '*.dll'
extension:
description: "Extension of the disassembly files. Default: .dasm"
required: true
default: '.dasm'
deleteAssemblies:
description: "Whether or not the assemblies should be deleted afterwards."
required: false
default: "false"
removeComments:
description: "Whether or not the lines starting with // should be removed from the disassembled files."
required: false
default: "false"
catchErrors:
description: "Whether or not errors should be handled."
required: false
outputs:
console:
description: "The console output of the command."
value: ${{ steps.ikdasm.outputs.console }}
runs:
using: 'composite'
steps:
- name: "Make temporary file of script."
id: script
uses: act/common/utils/mktemp@master
with:
input: ${{ github.action_path }}/disassemble_files.sh
tmpDir: .
- name: "Run ikdasm script."
id: ikdasm
uses: act/common/mono/mono@master
env:
DASM_EXTENSION: ${{ inputs.extension }}
with:
program: bash
command: ${{ steps.script.outputs.tmp }} "${{ inputs.directory }}" "${{ inputs.pattern }}" ${{ inputs.deleteAssemblies }} ${{ inputs.removeComments }}
catchErrors: ${{ inputs.catchErrors }}

View File

@@ -0,0 +1,26 @@
#!/bin/bash
# Get the directory and pattern as arguments
DIR=$1
PATTERN=$2
REMOVE_ORIGINAL=$3
REMOVE_COMMENTS=$4
DASM_EXTENSION=${DASM_EXTENSION:-".dasm"}
find "$DIR" -type f -name "$PATTERN" -print0 | while IFS= read -r -d '' file; do
# Disassemble the file and save it to a temporary file.
OUTFILE="${file}${DASM_EXTENSION}"
TMP=$(mktemp)
ikdasm "$file" > "$TMP"
if [[ "$REMOVE_COMMENTS" == "true" ]]; then
# Remove lines starting with //
sed -i '/^\/\//d' "$TMP"
fi
# Move the temporary file to the output file.
mv "$TMP" "$OUTFILE"
echo $(basename "$OUTFILE")
if [[ "$REMOVE_ORIGINAL" == "true" ]]; then
rm "$file"
fi
done

20
mono/mono/Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM debian:stable-slim
ENV NUGET_VERSION=v6.5.0
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
bash \
wget \
mono-complete \
tzdata
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*
RUN wget https://dist.nuget.org/win-x86-commandline/$NUGET_VERSION/nuget.exe -O /usr/bin/nuget.exe
RUN chmod +x /usr/bin/nuget.exe
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

24
mono/mono/action.yaml Normal file
View File

@@ -0,0 +1,24 @@
name: mono
description: "Run mono commands."
inputs:
command:
description: "Shell arguments to pass into mono."
required: true
program:
description: "Program to run instead of mono. Default: mono"
required: false
default: "mono"
catchErrors:
description: "Whether or not errors should be handled."
required: false
outputs:
console:
description: "The console output of the command."
runs:
env:
PROGRAM: ${{ inputs.program }}
CATCH_ERRORS: ${{ inputs.catchErrors }}
using: docker
image: Dockerfile
args:
- ${{ inputs.command }}

20
mono/mono/entrypoint.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
COMMAND="$@"
PROGRAM=${PROGRAM:-"mono"}
OUTPUT=$(bash -c "$PROGRAM $COMMAND")
RESULT=$?
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
echo "exitCode=$RESULT" >> "$GITHUB_OUTPUT"
if [[ "$CATCH_ERRORS" != "true" ]]; then
exit $RESULT
fi

View File

@@ -0,0 +1,79 @@
name: nuget-build-and-compare
description: "Pack a .nuspec file into a .nupkg."
inputs:
name:
description: "The name of the package."
required: true
input:
description: "The json input which will be converted into yaml."
required: true
defaultVersion:
description: "Version of the .nupkg file."
required: true
default: 1.0.0
outputDirectory:
description: "Directory for the output .nupkg."
required: true
url:
description: "Url of the GitHub server instance."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
username:
description: "Username for the nuget repository to search."
required: true
default: ${{ github.actor }}
password:
description: "Password or ApiKey of the nuget repository to search."
required: true
default: ${{ github.token }}
outputs:
nupkg:
description: "The generated output .nupkg file."
value: ${{ steps.package.outputs.nupkg }}
nupkgName:
description: "The generated output .nupkg file's name."
value: ${{ steps.package.outputs.nupkgName }}
hasChanged:
description: "Whether or not the .nupkg files match."
value: ${{ steps.compare.outputs.success != 'true' }}
runs:
using: "composite"
steps:
- name: "Get the next version of the package."
uses: act/common/nuget/nuget-get-next-branched-version@master
id: nuget
with:
name: ${{ inputs.name }}
defaultVersion: ${{ inputs.defaultVersion }}
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.password }}
- name: "Get yaml from json."
id: convert
uses: act/common/yq/yq-convert@master
with:
from: json
to: yaml
input: ${{ inputs.input }}
- name: "Build .nupkg."
id: package
uses: act/common/tpl/tpl-to-nupkg@master
with:
input: ${{ steps.convert.outputs.result }}
version: ${{ steps.nuget.outputs.nextVersion }}
outputDirectory: ${{ inputs.outputDirectory }}
- name: "Compare .nupkg to remote .nupkg."
if: ${{ steps.nuget.outputs.latestVersion }}
id: compare
uses: act/common/nuget/nuget-compare-version@master
with:
lhs: ${{ steps.package.outputs.nupkg }}
version: ${{ steps.nuget.outputs.latestVersion }}
name: ${{ inputs.name }}
username: ${{ inputs.username }}
password: ${{ inputs.password }}
url: ${{ inputs.url }}/_registry/nuget/${{ inputs.organization }}/index.json

View File

@@ -0,0 +1,69 @@
name: nuget-compare-version
description: "Download the desired .nupkg file and compare it to an existing .nupkg file."
inputs:
lhs:
description: "Path to the existing .nupkg file."
required: true
name:
description: "Name of the .nupkg file."
required: true
version:
description: "Version of the .nupkg file."
required: false
default: ""
prerelease:
description: "Install prerelease packages. Values: true, false."
required: false
default: "${{ github.event_name == 'pull_request' }}"
url:
description: "Url of the NuGet repository."
required: true
default: ${{ github.server_url }}/_registry/nuget/${{ github.repository_owner }}/index.json
username:
description: "Username for the nuget repository to search."
required: true
default: ${{ github.actor }}
password:
description: "Password or ApiKey of the nuget repository to search."
required: true
default: ${{ github.token }}
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
outputs:
success:
description: "Whether or not the .nupkg files match."
value: ${{ steps.compare.outputs.success }}
runs:
using: "composite"
steps:
- name: "Make temporary folder if we are using .nupkg only."
id: mktmp
uses: act/common/utils/mktemp@master
with:
tmpDir: ${{ inputs.tmpDir }}
outputType: dir
- name: "Get the desired version of the package."
id: install
uses: act/common/nuget/nuget-install@master
with:
name: ${{ inputs.name }}
version: ${{ inputs.version }}
prerelease: ${{ inputs.prerelease }}
url: ${{ inputs.url }}
username: ${{ inputs.username }}
password: ${{ inputs.password }}
outputDirectory: ${{ steps.mktmp.outputs.tmp }}
nupkgOnly: true
directDownload: true
cleanTmp: false
- name: "Compare the two .nupkg files."
id: compare
uses: act/common/utils/compare-nupkg@master
with:
lhs: ${{ inputs.lhs }}
rhs: ${{ steps.install.outputs.nupkg }}
- name: "Remove temporary files."
run: rm -rf "${{ inputs.tmpDir }}"
shell: bash

View File

@@ -0,0 +1,66 @@
name: nuget-get-next-branched-version
description: "Get the next version of a NuGet package based on the current branch status."
inputs:
name:
description: "The name of the package."
required: true
defaultVersion:
description: "Default version to use."
required: true
default: 1.0.0
url:
description: "Url of the GitHub server instance."
required: true
default: ${{ github.server_url }}
organization:
description: "Organization to search."
required: true
default: ${{ github.repository_owner }}
apiToken:
description: "Api Token for GitHub."
required: true
default: ${{ github.token }}
prerelease:
description: "Query prerelease packages. Values: true, false."
required: false
default: "${{ github.event_name == 'pull_request' }}"
outputs:
latestVersion:
description: "The current latest version for the .nupkg."
value: ${{ steps.nuget.outputs.version || steps.nugetFallback.outputs.version }}
nextVersion:
description: "The next version for the .nupkg file."
value: ${{ steps.version.outputs.nextVersion }}
runs:
using: "composite"
steps:
- name: "Get the base version for the package."
uses: act/common/utils/version-increment-branch@master
id: base
with:
version: ${{ inputs.defaultVersion }}
- uses: act/common/github/github-query-nuget-versions-latest@master
id: nuget
with:
name: ${{ inputs.name }}
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
filter: ^${{ steps.base.outputs.baseVersion }}
prerelease: ${{ inputs.prerelease }}
- name: "If no version is found, get the latest version for the package if we didn't already look for it."
uses: act/common/github/github-query-nuget-versions-latest@master
id: nugetFallback
if: ${{ steps.nuget.outputs.version == '' && inputs.prerelease != 'false' }}
with:
name: ${{ inputs.name }}
url: ${{ inputs.url }}
organization: ${{ inputs.organization }}
apiToken: ${{ inputs.apiToken }}
filter: ^${{ steps.base.outputs.majorMinorPatchVersion }}
prerelease: false
- name: "Get the next version for the package."
uses: act/common/utils/version-increment-branch@master
id: version
with:
version: ${{ steps.nuget.outputs.version || steps.nugetFallback.outputs.version || inputs.defaultVersion }}

View File

@@ -0,0 +1,135 @@
name: nuget-install
description: "Download the desired .nupkg file."
inputs:
name:
description: "Name of the .nupkg file."
required: true
version:
description: "Version of the .nupkg file."
required: false
default: ""
prerelease:
description: "Install prerelease packages. Values: true, false."
required: false
default: "false"
outputDirectory:
description: "Directory for the output file."
required: true
default: "."
directDownload:
description: "Download the .nupkg file directly from the source."
required: true
default: "true"
excludeVersion:
description: "Exclude the version when downloading the .nuget package."
required: true
default: "false"
nupkgOnly:
description: "Only output the .nupkg file directly to the output directory."
required: true
default: "false"
additionalArgs:
description: "Additional arguments to use when dowloading the .nupkg file."
required: false
source:
description: "Name of the source to use."
required: true
default: lewdorg
url:
description: "Url of the NuGet repository."
required: true
default: ${{ github.server_url }}/_registry/nuget/${{ github.repository_owner }}/index.json
username:
description: "Username for the nuget repository to search."
required: true
default: ${{ github.actor }}
password:
description: "Password or ApiKey of the nuget repository to search."
required: true
default: ${{ github.token }}
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
cleanTmp:
description: "Remove the temporary directory after use. Default: true"
required: true
default: "true"
outputs:
nupkg:
description: "The path to the .nupkg file."
value: ${{ steps.move.outputs.nupkg }}
runs:
using: "composite"
steps:
- name: "Make temporary folder if we are using .nupkg only."
id: mktmp
uses: act/common/utils/mktemp@master
with:
tmpDir: ${{ inputs.tmpDir }}
outputType: dir
- name: "Create Output Directory"
run: |
OUTPUT_DIR="${{ inputs.outputDirectory }}"
mkdir "$OUTPUT_DIR" -p
shell: bash
- name: "Build nuget command."
id: command
run: |
COMMAND="install ${{ inputs.name }} -OutputDirectory \"${{ steps.mktmp.outputs.tmp }}\" ${{ inputs.additionalArgs }}"
VERSION="${{ inputs.version }}"
PRERELEASE="${{ inputs.prerelease }}"
DIRECT="${{ inputs.directDownload }}"
if [ "$DIRECT" == "true" ]; then
COMMAND="$COMMAND -DirectDownload"
fi
if [ -n "$VERSION" ]; then
COMMAND="$COMMAND -Version $VERSION"
fi
if [ "$PRERELEASE" == "true" ]; then
COMMAND="$COMMAND -Prerelease"
fi
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Download the .nupkg file."
uses: act/common/nuget/nuget@master
with:
command: ${{ steps.command.outputs.command }}
username: ${{ inputs.username }}
password: ${{ inputs.password }}
source: ${{ inputs.source }}
url: ${{ inputs.url }}
- name: "Take ownership of the artifacts."
uses: act/common/utils/chown@master
with:
file: ${{ steps.mktmp.outputs.tmp }}
- name: "Copy contents to output folder."
id: move
run: |
OUTPUT_DIR="${{ inputs.outputDirectory }}"
TMP_DIR="${{ steps.mktmp.outputs.tmp }}"
EXCLUDE_VERSION="${{ inputs.excludeVersion }}"
NUPKG_ONLY="${{ inputs.nupkgOnly }}"
if [ "$EXCLUDE_VERSION" == "true" ]; then
NUPKG_NAME="${{ inputs.name }}.nupkg"
else
# Get the subdirectory name
OUTDIR=($TMP_DIR/*)
BASE_NAME=$(basename "$OUTDIR")
NUPKG_NAME="${BASE_NAME}.nupkg"
fi
if [ "$NUPKG_ONLY" == "true" ]; then
mv "$OUTDIR/$NUPKG_NAME" "$OUTPUT_DIR"
echo "nupkg=$OUTPUT_DIR/$NUPKG_NAME" >> "$GITHUB_OUTPUT"
else
mv "$TMP_DIR"/* "$OUTPUT_DIR"
echo "nupkg=$OUTPUT_DIR/$OUTDIR/$NUPKG_NAME" >> "$GITHUB_OUTPUT"
fi
shell: bash
- name: "Remove temporary files."
if: ${{ inputs.cleanTmp == 'true' }}
run: rm -rf "${{ inputs.tmpDir }}"
shell: bash

View File

@@ -0,0 +1,37 @@
name: nuget-pack
description: "Pack a .nuspec file into a .nupkg."
inputs:
nuspec:
description: "The .nuspec file or configuration to pack."
required: true
version:
description: "Version of the .nupkg file."
required: true
outputDirectory:
description: "Directory for the output file."
required: true
additionalArgs:
description: "Additional arguments to use when packing the .nuspec file."
required: false
runs:
using: "composite"
steps:
- name: "Make temporary file of nuspec."
id: tmp
uses: act/common/utils/mktemp@master
with:
input: ${{ inputs.nuspec }}
tmpDir: .
additionalArgs: --suffix=.nuspec
- name: "Create Output Directory"
run: |
OUTPUT_DIR="${{ inputs.outputDirectory }}"
mkdir "$OUTPUT_DIR" -p
shell: bash
- name: "Build the .nupkg file."
uses: act/common/nuget/nuget@master
with:
command: pack "${{ steps.tmp.outputs.tmp }}" -OutputDirectory "${{ inputs.outputDirectory }}" -Version "${{ inputs.version }}" ${{ inputs.additionalArgs }}
- name: "Remove temporary files."
run: rm -rf "${{ steps.tmp.outputs.tmp }}"
shell: bash

View File

@@ -0,0 +1,37 @@
name: nuget-upload-nupkg
description: "Upload a nupkg to a NuGet repository."
inputs:
package:
description: "Name of the package to search for."
required: true
source:
description: "Name of the source to use."
required: true
default: lewdorg
url:
description: "Url of the NuGet repository."
required: true
default: ${{ github.server_url }}/_registry/nuget/${{ github.repository_owner }}/index.json
username:
description: "Username for the nuget repository to search."
required: true
default: ${{ github.actor }}
password:
description: "Password or ApiKey of the nuget repository to search."
required: true
default: ${{ github.token }}
options:
description: "Additional options when uploading."
required: false
runs:
using: "composite"
steps:
- name: "Run nuget push."
id: nuget
uses: act/common/nuget/nuget@master
with:
command: push ${{ inputs.package }} -Source ${{ inputs.source }} ${{ inputs.options }}
username: ${{ inputs.username }}
password: ${{ inputs.password }}
source: ${{ inputs.source }}
url: ${{ inputs.url }}

20
nuget/nuget/Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM debian:stable-slim
ENV VERSION=v6.5.0
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
bash \
wget \
mono-complete \
tzdata
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*
RUN wget https://dist.nuget.org/win-x86-commandline/$VERSION/nuget.exe -O /usr/bin/nuget.exe
RUN chmod +x /usr/bin/nuget.exe
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

39
nuget/nuget/action.yaml Normal file
View File

@@ -0,0 +1,39 @@
name: nuget
description: "Run a nuget command."
inputs:
command:
description: "Nuget command to run."
required: false
catchErrors:
description: "Whether or not errors should be handled."
required: false
source:
description: "Name of the source to use."
required: false
default: origin
url:
description: "Url of the NuGet repository."
required: false
default: ${{ github.server_url }}/_registry/nuget/${{ github.repository_owner }}/index.json
username:
description: "Username for the nuget repository to search."
required: false
default: ${{ github.actor }}
password:
description: "Password or ApiKey of the nuget repository to search."
required: false
default: ${{ github.token }}
outputs:
console:
description: "The console output of the command."
runs:
using: 'docker'
image: 'Dockerfile'
env:
NUGET_SOURCE_NAME: ${{ inputs.source }}
NUGET_SOURCE_URL: ${{ inputs.url }}
NUGET_SOURCE_USERNAME: ${{ inputs.username }}
NUGET_SOURCE_PASSWORD: ${{ inputs.password }}
CATCH_ERRORS: ${{ inputs.catchErrors }}
args:
- ${{ inputs.command }}

32
nuget/nuget/entrypoint.sh Normal file
View File

@@ -0,0 +1,32 @@
#!/bin/bash
#TODO: Reweite this action to make use of act/common/mono/mono
function nuget
{
mono /usr/bin/nuget.exe $@
}
if [[ -n "$NUGET_SOURCE_NAME" && -n "$NUGET_SOURCE_URL" && -n "$NUGET_SOURCE_USERNAME" && -n "$NUGET_SOURCE_PASSWORD" ]]; then
nuget source remove -Name "$NUGET_SOURCE_NAME"
nuget source add -Name "$NUGET_SOURCE_NAME" -Source "$NUGET_SOURCE_URL" -Username "$NUGET_SOURCE_USERNAME" -Password "$NUGET_SOURCE_PASSWORD"
SET_SOURCE=true
fi
OUTPUT=$(bash -c "mono /usr/bin/nuget.exe $@")
RESULT=$?
echo "$OUTPUT"
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
if [[ -n "$SET_SOURCE" ]]; then
nuget source remove -Name "$NUGET_SOURCE_NAME"
fi
if [[ "$CATCH_ERRORS" != "true" ]]; then
exit $RESULT
fi

View File

@@ -0,0 +1,73 @@
name: renpy-distribute
description: "Build a RenPy project for various platforms."
inputs:
project:
description: "Path to the RenPy project."
required: true
package:
description: "The specific package to build. Values: win, mac, linux, android, pc, market" #TODO: android
required: true
dest:
description: "Destination folder for the builds."
required: false
packageDest:
description: "Destination folder for the indivdual package."
required: false
archive:
description: "Whether or not to compress the build into a zip file."
required: true
default: "true"
format:
description: "The archive format to use. Values: zip, tar.bz2 Default: zip"
required: true
default: "zip"
additionalArgs:
description: "Additional arguments to pass into RenPy."
required: false
outputs:
package:
description: "The path to the package or packages."
value: ${{ steps.command.outputs.output }}
runs:
using: "composite"
steps:
- name: "Build command."
id: command
run: |
# Replace each space with a backslash and a space
PROJECT="${{ inputs.project }}"
PROJECT="${PROJECT// /\\ }"
COMMAND="distribute $PROJECT --package ${{ inputs.package }} ${{ inputs.additionalArgs }}"
ARCHIVE="${{ inputs.archive }}"
if [[ "$ARCHIVE" == "false" ]]; then
COMMAND="$COMMAND --no-archive"
EXT=""
else
EXT=".${{ inputs.format }}"
fi
DEST="${{ inputs.dest }}"
if [[ -n "$DEST" ]]; then
OUTPUT="$DEST"
mkdir -p "$DEST"
COMMAND="$COMMAND --destination $DEST"
fi
FORMAT="${{ inputs.format }}"
if [[ -n "$FORMAT" ]]; then
COMMAND="$COMMAND --format $FORMAT"
fi
PACKAGE_DEST="${{ inputs.packageDest }}"
if [[ -n "$PACKAGE_DEST" ]]; then
OUTPUT="${PACKAGE_DEST}${EXT}"
mkdir -p "$PACKAGE_DEST"
COMMAND="$COMMAND --packagedest $PACKAGE_DEST"
fi
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
echo "output=$OUTPUT" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Run RenPy distribute command."
uses: act/common/renpy/renpy@master
with:
command: ${{ steps.command.outputs.command }}
catchErrors: true

8
renpy/renpy/Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
# Container image that runs your code
FROM maienm/renpy:8.1.0
ENV RENPY_HOME="/opt/renpy/"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

21
renpy/renpy/action.yaml Normal file
View File

@@ -0,0 +1,21 @@
name: renpy
description: "Run RenPy commands."
inputs:
command:
description: "Arguments to pass into RenPy."
required: true
catchErrors:
description: "Whether or not errors should be handled."
required: false
outputs:
console:
description: "The console output of the RenPy command."
exitCode:
description: "How the program exited."
runs:
using: docker
image: Dockerfile
env:
CATCH_ERRORS: ${{ inputs.catchErrors }}
args:
- ${{ inputs.command }}

27
renpy/renpy/entrypoint.sh Normal file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
ARGS="$@"
set -o pipefail
exec 5>&1
OUTPUT=$(bash -c "$RENPY_HOME/renpy.sh $RENPY_HOME/launcher $ARGS" | tee /dev/fd/5)
RESULT=$?
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
# if [[ -n "$OUTPUT" ]]; then
# echo "console<<EOF" >> "$GITHUB_OUTPUT"
# echo "$OUTPUT" >> "$GITHUB_OUTPUT"
# echo "EOF" >> "$GITHUB_OUTPUT"
# fi
if [[ -n "$OUTPUT" ]]; then
OUTPUT="${OUTPUT//'%'/'%25'}"
OUTPUT="${OUTPUT//$'\n'/'%0A'}"
OUTPUT="${OUTPUT//$'\r'/'%0D'}"
echo "::set-output name=console::$OUTPUT"
fi
echo "exitCode=$RESULT" >> "$GITHUB_OUTPUT"
if [[ "$CATCH_ERRORS" != "true" ]]; then
exit $RESULT
fi

View File

@@ -0,0 +1,20 @@
name: rpm-verifysign
description: "Verify the signature a given .rpm file with a given .gpg key."
inputs:
file:
description: "File to verify."
required: true
gpgKey:
description: "GPG public key to check with. Can be a file or raw key."
required: true
runs:
using: "composite"
steps:
- run: cp -f ${{ github.action_path }}/verify_file.sh _verify_file.sh
shell: bash
- name: "Verify file."
uses: act/common/distros/rockylinux@master
with:
args: bash "_verify_file.sh" "${{ inputs.file }}" "${{ inputs.gpgKey }}"
- run: rm _verify_file.sh
shell: bash

View File

@@ -0,0 +1,22 @@
#!/bin/bash
#Importing gpg key via cli
#https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors
FILE="$1"
GPG_KEY="$2"
TMP_KEY_PATH="/tmp_key.gpg"
if [[ ! -f "$GPG_KEY" ]]; then
cat <<EOF > "$TMP_KEY_PATH"
$GPG_KEY
EOF
GPG_KEY="$TMP_KEY_PATH"
fi
#Only seems to import files, not STDIN.
#gpg --import does not work with 'rpm -K'
rpm --import "$GPG_KEY"
rm -f "$TMP_KEY_PATH"
rpm -K $FILE
exit $?

View File

@@ -0,0 +1,34 @@
name: rpmsign-file
description: "Sign a given .rpm file with a given .gpg key."
inputs:
file:
description: "File to sign."
required: true
gpgKey:
description: "GPG key to sign with."
required: true
gpgPass:
description: "Password to the GPG key."
required: true
outputs:
publicKey:
description: "Public GPG key of the signed file."
value: ${{ steps.sign.outputs.publicKey }}
runs:
using: "composite"
steps:
- run: cp -f ${{ github.action_path }}/sign_file.sh _sign_file.sh
shell: bash
- name: "Sign file."
id: sign
uses: act/common/distros/rockylinux@master
with:
#Having single quotes around "${{ inputs.gpgKey }}" makes it work in act.
args: bash "_sign_file.sh" "${{ inputs.file }}" "${{ inputs.gpgKey }}" "${{ inputs.gpgPass }}"
- run: rm _sign_file.sh
shell: bash
- name: "Own artifacts."
uses: act/common/utils/chown@master
with:
file: ${{ inputs.file }}

View File

@@ -0,0 +1,41 @@
#!/bin/bash
#Importing gpg key via cli
#https://d.sb/2016/11/gpg-inappropriate-ioctl-for-device-errors
FILE="$1"
GPG_KEY="$2"
GPG_PASS="$3"
GPG_DIR="/root/.gnupg"
mkdir -p "$GPG_DIR"
if [[ -f "$GPG_KEY" ]]; then
GPG_KEY=$(cat "$GPG_KEY")
fi
#Trim single quotes if it has any. (Single quotes are needed for ACT)
GPG_KEY=$(echo "$GPG_KEY" | tr -d \')
gpg --homedir "$GPG_DIR" --allow-secret-key-import --import --batch --passphrase "$GPG_PASS" <<EOF
$GPG_KEY
EOF
gpg --homedir "$GPG_DIR" --list-keys
#Get name with email, then cut it to get just the name.
SIGNER_NAME=$(gpg --homedir "$GPG_DIR" --with-colons --list-keys | grep uid: | cut -d ':' -f 10 | cut -d '<' -f 1 | xargs)
rpmsign --define "_gpg_name $SIGNER_NAME" --define "_gpg_sign_cmd_extra_args --homedir $GPG_DIR --pinentry-mode loopback --passphrase $GPG_PASS" --addsign "$FILE"
SIGNER=$(rpm -qpi simbaspark-2.6.29.1049-1.x86_64.rpm | grep "Signature" | cut -d ':' -f 2 | xargs)
RESULT=$?
if [[ "$SIGNER" == "(none)" ]]; then
RESULT=1
fi
#Set the public key as output.
PUBLIC_KEY=$(gpg --homedir "$GPG_DIR" --armor --export "$SIGNER_NAME")
PUBLIC_KEY="${PUBLIC_KEY//'%'/'%25'}"
PUBLIC_KEY="${PUBLIC_KEY//$'\n'/'%0A'}"
PUBLIC_KEY="${PUBLIC_KEY//$'\r'/'%0D'}"
echo "publicKey=$PUBLIC_KEY" >> "$GITHUB_OUTPUT"
exit $RESULT

32
tpl/tpl-env/action.yaml Normal file
View File

@@ -0,0 +1,32 @@
name: tpl-env
description: "Format a Go template file given yaml input. The input has yaml file environment variables replaced first."
inputs:
template:
description: "Template or local path of the template file."
required: true
decoder:
description: "Decoder format. Supported values: json, yaml, toml"
required: true
default: yaml
input:
description: "Input or local path of the input data file."
required: true
outputs:
result:
description: "Local path of the output file."
value: ${{ steps.template.outputs.result }}
runs:
using: "composite"
steps:
- name: "Substitute Environment Variables"
id: envsubst
uses: act/common/utils/envsubst@master
with:
input: ${{ inputs.input }}
- name: "Build Template"
id: template
uses: act/common/tpl/tpl-file@master
with:
template: ${{ inputs.template }}
decoder: ${{ inputs.decoder }}
input: ${{ steps.envsubst.outputs.result }}

45
tpl/tpl-file/action.yaml Normal file
View File

@@ -0,0 +1,45 @@
name: tpl-file
description: "Format a Go template file given a yaml input file."
inputs:
template:
description: "Template or local path of the template file."
required: true
decoder:
description: "Decoder format. Supported values: json, yaml, toml"
required: true
default: yaml
input:
description: "Input or local path of the input data file."
required: true
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
outputs:
result:
description: "Local path of the output file."
value: ${{ steps.template.outputs.console }}
runs:
using: "composite"
steps:
- name: "Make temporary file of template."
id: mktmp-template
uses: act/common/utils/mktemp@master
with:
input: ${{ inputs.template }}
tmpDir: ${{ inputs.tmpDir }}
- name: "Make temporary file of input."
id: mktmp-input
uses: act/common/utils/mktemp@master
with:
input: ${{ inputs.input }}
tmpDir: ${{ inputs.tmpDir }}
- name: "Generate template."
id: template
uses: act/common/tpl/tpl@master
with:
command: --file "${{ steps.mktmp-template.outputs.tmp }}" --decoder ${{ inputs.decoder }} < "${{ steps.mktmp-input.outputs.tmp }}"
- name: "Remove temporary files."
run: rm -rf "${{ inputs.tmpDir }}"
shell: bash

View File

@@ -0,0 +1,38 @@
name: tpl-to-dir
description: "Format a Go template file given a yaml input file to a file of the same name in the specified output directory. The input yaml file environment variables replaced first."
inputs:
templateFile:
description: "Local path to the template file."
required: true
inputFilename:
description: "Name of the input file without directories or extensions."
required: true
inputExtension:
description: "Extension for the input file."
required: false
default: .yaml
outputExtension:
description: "Extension for the output file."
required: false
inputDirectory:
description: "Directory for the input files."
required: false
outputDirectory:
description: "Directory for the output files."
required: false
outputs:
outputFile:
description: "The generated output file."
value: ${{ inputs.outputDirectory }}/${{ inputs.inputFilename }}${{ inputs.outputExtension }}
runs:
using: "composite"
steps:
- name: "Create Output Directory"
run: mkdir ${{ inputs.outputDirectory }} -p
shell: bash
- name: "Generate Template"
uses: act/common/tpl/tpl-env@master
with:
templateFile: ${{ inputs.inputDirectory }}/${{ inputs.templateFile }}
inputFile: ${{ inputs.inputDirectory }}/${{ inputs.inputFilename }}${{ inputs.inputExtension }}
outputFile: ${{ inputs.outputDirectory }}/${{ inputs.inputFilename }}${{ inputs.outputExtension }}

View File

@@ -0,0 +1,50 @@
name: tpl-to-nupkg
description: "Pack a .nupkg given a .nuspec Go template file and a yaml input file. The input yaml file environment variables replaced first."
inputs:
template:
description: "Template or local path of the template file to use. Defaults to the template file in the action's directory."
required: false
input:
description: "Input or local path of the yaml input data file."
required: true
version:
description: "Version of the .nupkg file."
required: true
outputDirectory:
description: "Directory for the output file."
required: true
default: '.'
nuspecExtension:
description: "Extension for the output file."
required: false
default: .nuspec
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
outputs:
nuspec:
description: "The generated output .nuspec file."
value: ${{ steps.template.outputs.result }}
nupkg:
description: "The generated output .nupkg file."
value: ${{ inputs.outputDirectory }}/${{ steps.nuspec.outputs.packageName }}.${{ inputs.version }}.nupkg
nupkgName:
description: "The generated output .nupkg file's name."
value: ${{ steps.nuspec.outputs.packageName }}.${{ inputs.version }}.nupkg
runs:
using: "composite"
steps:
- name: "Generate Nuspec From Template"
id: nuspec
uses: act/common/tpl/tpl-to-nuspec@master
with:
template: ${{ inputs.template }}
input: ${{ inputs.input }}
- name: "Build the .nupkg file."
uses: act/common/nuget/nuget-pack@master
with:
nuspec: ${{ steps.nuspec.outputs.nuspec }}
version: ${{ inputs.version }}
outputDirectory: ${{ inputs.outputDirectory }}

View File

@@ -0,0 +1,67 @@
name: tpl-to-nuspec
description: "Pack a .nupkg given a .nuspec Go template file and a yaml input file. The input yaml file environment variables replaced first."
inputs:
template:
description: "Template or local path of the template file to use. Defaults to the template file in the action's directory."
required: false
input:
description: "Input or local path of the yaml input data file."
required: true
outputs:
nuspec:
description: "The generated output .nuspec file."
value: ${{ steps.xml.outputs.result }}
packageName:
description: "The 'name' property of the generated .nuspec file."
value: ${{ steps.name.outputs.result }}
runs:
using: "composite"
steps:
- name: "Set template variable."
id: get-template
run: |
TEMPLATE=$(cat << EOF
${{ inputs.template }}
EOF
)
if [[ -z "$TEMPLATE" ]]; then
TEMPLATE="${{ github.action_path }}/nuspec.yaml.tpl"
fi
echo "template<<EOF" >> "$GITHUB_OUTPUT"
echo "$TEMPLATE" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Merge Input"
id: merge
uses: act/common/yq/yq-merge@master
with:
lhs: ${{ github.action_path }}/defaults.yaml
rhs: ${{ inputs.input }}
- name: "Generate Nuspec Yaml from Template"
id: template
uses: act/common/tpl/tpl-env@master
with:
template: ${{ steps.get-template.outputs.template }}
decoder: yaml
input: ${{ steps.merge.outputs.result }}
- name: "Convert the Nuspec Yaml to XML"
id: trim
uses: act/common/yq/yq-trim@master
with:
input: ${{ steps.template.outputs.result }}
recursive: true
- name: "Convert the Nuspec Yaml to XML"
id: xml
uses: act/common/yq/yq-convert@master
with:
input: ${{ steps.trim.outputs.result }}
from: yaml
to: xml
- name: "Get id from input."
id: name
uses: act/common/yq/yq-expression@master
with:
input: ${{ steps.merge.outputs.result }}
expression: .id

View File

@@ -0,0 +1,16 @@
authors:
- lewdorg Inc
name: ${GITHUB_REPOSITORY}
version: 0.0.0-dev
projectUrl: https://lewdorg.com
iconUrl: https://lewdorg.com/wp-content/uploads/2022/03/cropped-lewdorg-Profile-Circle-Light-1-1-270x270.png
copyright: '© Copyright {{ now | date "2006" }} lewdorg Inc, Patents Issued.'
repository:
type: git
url: git@github.lewdorg.com:${GITHUB_REPOSITORY}.git
branch: ${GITHUB_REF_NAME}
commit: ${GITHUB_SHA}
tags:
- lewdorg
requireLicenseAcceptance: false
language: en-US

View File

@@ -0,0 +1,67 @@
# This file provides an example for the desired Yaml format for a .nuspec file.
# Required Metadata
id: Example.Package
version: 1.0.0
description: This is an example package.
authors:
- John Doe
# Optional Metadata
title: Example Package
license:
content: MIT
type: expression
projectUrl: https://example.com
iconUrl: icon.png
icon:
src: icon.png
target: icon.png
requireLicenseAcceptance: false
developmentDependency: true
summary: This is a summary of the example package.
releaseNotes: This is the first release of the example package.
language: en-US
tags:
- example
- tag1
- tag2
repository:
type: git
url: https://github.com/example/example.package
branch: master
commit: 0a1b2c3d
path: /root
# Content
content:
path: /content
files:
- include: any/any/config.json
buildAction: Content
copyToOutput: "true"
flatten: "true"
# Source Files
source:
path: /source
groups:
- framework: .NETStandard2.0
references:
- name: System.Data
dependencies:
- id: Example.Dependency
version: 1.0.0
exclude:
- Build
- Analyzers
files:
- name: Example.Package.dll
- name: Example.Package.pdb
dlls:
- name: Unity.Package
- files:
- name: icon.png
target: content
- framework: net40
assemblies:
- name: System.IO

View File

@@ -0,0 +1,133 @@
+p_xml: version="1.0" encoding="utf-8"
package:
+@xmlns: http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd
metadata:
id: {{ .id | default "" }}
version: {{ .version | default "" }}
description: {{ .description | default "" }}
authors: "{{ join ", " .authors | default "" }}"
title: {{ .title | default "" }}
projectUrl: {{ .projectUrl | default "" }}
licenseUrl: {{ .licenseUrl | default "" }}
{{- with .license }}
license:
{{- if .content }}
+content: {{ .content }}
{{- end }}
{{- if .type }}
+@type: {{ .type }}
{{- end }}
{{- end }}
icon: {{ .icon | default "" }}
iconUrl: {{ .iconUrl | default "" }}
requireLicenseAcceptance: {{ .requireLicenseAcceptance | default "" }}
developmentDependency: {{ .developmentDependency | default "" }}
{{- if .copyright }}
copyright: {{ tpl (toYaml .copyright) $ }}
{{- end }}
summary: {{ .summary | default "" }}
releaseNotes: {{ .releaseNotes | default "" }}
language: {{ .language | default "" }}
tags: "{{ join ", " .tags | default "" }}"
{{- with .repository }}
repository:
{{- if .type }}
+@type: {{ .type }}
{{- end }}
{{- if .url }}
+@url: {{ .url }}
{{- end }}
{{- if .branch }}
+@branch: {{ .branch }}
{{- end }}
{{- if .commit }}
+@commit: {{ .commit }}
{{- end }}
{{- end }}
{{- with $.source }}
{{- $path := print (default "." $.path) "/" (default "." .path) | clean }}
dependencies:
group:
{{- range $item := .groups }}
{{- if and $item.framework }}
- +@targetFramework: {{ $item.framework }}
dependency:
{{- range $dep := $item.dependencies }}
- +@id: {{ $dep.id }}
+@version: {{ $dep.version }}
+@exclude: "{{ join ", " $dep.exclude }}"
{{- end }}
{{- end }}
{{- end }}
references:
group:
{{- range $item := .groups }}
{{- if and $item.framework $item.references }}
- +@targetFramework: {{ $item.framework }}
{{- range $ref := $item.references }}
- reference:
+@file: {{ print $path "/" $ref.name | clean }}
{{- end }}
{{- end }}
{{- end }}
frameworkAssemblies:
frameworkAssembly:
{{- range $item := .groups }}
{{- range $ref := $item.assemblies }}
- +@assemblyName: {{ $ref.name }}
{{- if $item.framework }}
+@targetFramework: {{ $item.framework }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- with $.content }}
{{- $path := print (default "." $.path) "/" (default "." .path) | clean }}
contentFiles:
files:
{{- range $file := .files }}
- +@include: {{ print $path "/" $file.include | clean }}
{{- if $file.exclude }}
+@exclude: {{ print $path "/" $file.exclude | clean }}
{{- end }}
{{- if $file.buildAction }}
+@buildAction: {{ $file.buildAction }}
{{- end }}
{{- if $file.copyToOutput }}
+@copyToOutput: {{ $file.copyToOutput }}
{{- end }}
{{- if $file.flatten }}
+@flatten: {{ $file.flatten }}
{{- end }}
{{- end }}
{{- end }}
{{- with $.source }}
{{- $path := print (default "." $.path) "/" (default "." .path) | clean }}
files:
file:
{{- range $item := .groups }}
{{- range $file := $item.files }}
- +@src: {{ print $path "/" $file.name | clean }}
{{- if $item.framework }}
+@target: {{ print "lib/" $item.framework "/" (default $file.target ".") | clean }}
{{- else if $file.target }}
+@target: {{ $file.target }}
{{- end }}
{{- if $file.exclude }}
+@exclude: {{ print $path "/" $file.exclude | clean }}
{{- end }}
{{- end }}
{{- if $item.framework }}
{{- range $dll := $item.dlls }}
- +@src: {{ print $path "/" $dll.name ".dll" | clean }}
+@target: {{ print "lib/" $item.framework "/" (default $item.target ".") | clean }}
{{- if ($dll.hasPdb | default true) }}
- +@src: {{ print $path "/" $dll.name ".pdb" | clean }}
+@target: {{ print "lib/" $item.framework "/" (default $item.target ".") | clean }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

12
tpl/tpl/Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM debian:stable-slim
ENV VERSION=v0.2.0
RUN apt-get update
RUN apt-get install wget -y
RUN wget https://github.com/bluebrown/go-template-cli/releases/download/$VERSION/tpl-linux-amd64 -O /usr/bin/tpl
RUN chmod +x /usr/bin/tpl
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

21
tpl/tpl/action.yaml Normal file
View File

@@ -0,0 +1,21 @@
name: tpl
description: "Format a Go template file given yaml file."
inputs:
command:
description: "Arguments to pass into tpl."
required: false
catchErrors:
description: "Whether or not errors should be handled."
required: false
outputs:
console:
description: "The console output of the tpl command."
exitCode:
description: "How the program exited."
runs:
using: 'docker'
image: 'Dockerfile'
env:
CATCH_ERRORS: ${{ inputs.catchErrors }}
args:
- ${{ inputs.command }}

20
tpl/tpl/entrypoint.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
#See https://github.com/bluebrown/go-template-cli
ARGS="$@"
OUTPUT=$(sh -c "tpl $ARGS")
RESULT=$?
#Output multiline strings.
#https://trstringer.com/github-actions-multiline-strings/
if [[ -n "$OUTPUT" ]]; then
echo "console<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
echo "exitCode=$RESULT" >> "$GITHUB_OUTPUT"
if [[ "$CATCH_ERRORS" != "true" ]]; then
exit $RESULT
fi

View File

@@ -0,0 +1,22 @@
#Arg is replaced with the desired Unity container.
ARG IMAGE=unityci/base:latest
FROM ${IMAGE}
RUN apt update
RUN apt install -y wget chromium-browser
#ADD https://minio.studiowhy.net/hackmd/UnityBuilder /usr/local/bin/
COPY UnityBuilder /usr/local/bin/
RUN chmod +x /usr/local/bin/UnityBuilder
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
COPY scripts/. /scripts
# Commented out until better image selection is enabled.
# RUN --mount=type=secret,id=SERIAL \
# --mount=type=secret,id=USERNAME \
# --mount=type=secret,id=PASSWORD \
# bash /scripts/activate_license.sh
ENTRYPOINT ["/entrypoint.sh"]

Binary file not shown.

View File

@@ -0,0 +1,84 @@
name: unity-command
description: "Run a Unity command using a specified version of Unity."
inputs:
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
version:
description: "Unity Version."
required: true
imageTag:
description: "Tag to use for the temporary version of Unity. Must refer to an existing public Docker image. Must be the same is in the Dockerfile of the called action."
required: true
default: unityci/base:latest
serial:
description: "Unity license serial number. Or 'public' for a public license."
required: true
default: public
email:
description: "Unity email."
required: true
password:
description: "Unity password."
required: true
command:
description: "Unity command to run."
required: false
noGraphics:
description: "Whether or not to use the graphics device when running Unity."
required: false
default: "true"
unityBuilder:
description: "Whether or not to use the UnityBuilder instead of a Unity command."
required: false
removeContainer:
description: "Remove the mock container after building."
required: false
default: "true"
runs:
using: "composite"
steps:
- name: "Get Unity container name."
id: getContainer
uses: act/unity/unity-get-container@master
with:
version: ${{ inputs.version }}
platform: ${{ inputs.platform }}
- name: "Pull Unity container."
run: |
CONTAINER="${{ steps.getContainer.outputs.container }}"
CACHED_CONTAINER="$CONTAINER-activated"
# Activate the license on build.
# DOCKER_BUILDKIT=1 \
# SERIAL="${{ inputs.serial }}" USERNAME="${{ inputs.email }}" PASSWORD="${{ inputs.password }}" \
# docker build --secret id=SERIAL,env=SERIAL --secret id=USERNAME,env=USERNAME --secret id=PASSWORD,env=PASSWORD \
# -t $CACHED_CONTAINER --build-arg IMAGE=$CONTAINER ${{ github.action_path }}
docker build -t $CACHED_CONTAINER --build-arg IMAGE=$CONTAINER ${{ github.action_path }}
docker tag $CACHED_CONTAINER ${{ inputs.imageTag }}
shell: bash
- name: "Get Unity Command."
id: command
run: |
COMMAND="${{ inputs.command }}"
NO_GRAPHICS="${{ inputs.noGraphics }}"
if [[ "$NO_GRAPHICS" == "true" ]]; then
COMMAND="-nographics $COMMAND"
fi
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
- name: "Run Unity command."
uses: act/unity/unity@master
with:
serial: ${{ inputs.serial }}
# serial: "activated"
email: ${{ inputs.email }}
password: ${{ inputs.password }}
command: ${{ steps.command.outputs.command }}
unityBuilder: ${{ inputs.unityBuilder }}
- name: "Remove temporary image."
if: ${{ inputs.removeContainer == 'true' }}
run: |
docker image rm ${{ inputs.imageTag }}
shell: bash

View File

@@ -0,0 +1,24 @@
#!/bin/bash
SERIAL=$1; EMAIL=$2; PASSWORD=$3; COMMAND=$4; UNITY_BUILDER=$5
DEFAULT_ARGS="-quit -logFile -"
rm -rf $HOME/.config/unity3d
rm -rf /home/unity/.config/unity3d
#Add ssh key information for resolving packages.
bash /scripts/add_ssh_keys.sh
if [[ "$SERIAL" != "activated" ]]; then
echo "::group::Activating Unity License"
bash /scripts/activate_license.sh "$SERIAL" "$EMAIL" "$PASSWORD"
echo "::endgroup::"
fi
echo "::group::Running Unity Command"
#Run the command.
if [[ -n "$UNITY_BUILDER" ]]; then
UnityBuilder $COMMAND
else
unity-editor $DEFAULT_ARGS $COMMAND
fi
echo "::endgroup::"

View File

@@ -0,0 +1,29 @@
#!/bin/bash
SERIAL=$1; USERNAME=$2; PASSWORD=$3;
function check_path
{
local SECRET_PATH="/run/secrets"
local ENV_NAME="$1"
local ENV_VALUE="${!ENV_NAME}"
local FILE_PATH="$SECRET_PATH/$ENV_NAME"
if [[ -z "$ENV_VALUE" && -f "$FILE_PATH" ]]; then
export $ENV_NAME=$(cat "$FILE_PATH")
fi
}
check_path SERIAL
check_path USERNAME
check_path PASSWORD
if [[ -z "$SERIAL" || -z "$USERNAME" || -z "$PASSWORD" ]]; then
exit 0
fi
#Activate Unity
if [[ "$SERIAL" == "personal" ]]; then
UnityBuilder activate -i /usr/bin/unity-editor -u $USERNAME -p $PASSWORD
else
unity-editor $DEFAULT_ARGS -serial $SERIAL -username $USERNAME -password $PASSWORD
fi

View File

@@ -0,0 +1,17 @@
#!/bin/bash
if [[ -n "$SSH_PUBLIC_KEY" && -n "$SSH_PRIVATE_KEY" ]]; then
echo "ADDING SSH KEYS!"
SSH_DIR="/home/$(whoami)/.ssh"
mkdir -p $SSH_DIR
echo "$SSH_PUBLIC_KEY" > $SSH_DIR/id_rsa.pub
echo "$SSH_PRIVATE_KEY" > $SSH_DIR/id_rsa
cat << EOF > $SSH_DIR/config
Host *
StrictHostKeyChecking no
EOF
chmod 600 $SSH_DIR/id_rsa
chmod 644 $SSH_DIR/id_rsa.pub
cat $SSH_DIR/config
fi

View File

@@ -0,0 +1,77 @@
name: unity-composite
description: "Run a Unity command using a project's version and a build target. Then compress the result to a zip file."
inputs:
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
email:
description: "Unity email."
required: true
password:
description: "Unity password."
required: true
command:
description: "Unity command to run."
required: false
unityBuilder:
description: "Whether or not to use the UnityBuilder instead of a Unity command."
required: false
buildDir:
description: "Where the built application ends up."
required: false
default: build
cacheVolume:
description: "Name of the volume to cache the Library folder to."
required: false
artifactsVolume:
description: "Name of the volume to copy the artifacts to."
required: true
artifactsDir:
description: "Name of the directory to copy the artifacts from."
required: true
default: artifacts
noGraphics:
description: "Whether or not to use the graphics device when running Unity."
required: false
default: "true"
zipName:
description: "Name of the resulting zip file."
required: false
artifactMode:
description: "The mode with which to publish artifacts. Options: copy, own, or null Default: copy"
required: false
default: ""
runs:
using: "composite"
steps:
- name: "Checkout"
uses: actions/checkout@v2
- uses: act/unity/unity-project@master
with:
platform: ${{ inputs.platform }}
email: ${{ inputs.email }}
password: ${{ inputs.password }}
command: ${{ inputs.command }}
unityBuilder: ${{ inputs.unityBuilder }}
cacheVolume: ${{ inputs.cacheVolume }}
noGraphics: ${{ inputs.noGraphics }}
- name: "Compress build"
if: ${{ inputs.zipName }}
env:
WORKDIR: ${{ inputs.buildDir }}
uses: act/common/utils/compress@master
with:
name: ../${{ inputs.artifactsDir }}/${{ inputs.zipName }}
files: .
- name: "Own artifacts"
if: inputs.artifactMode == 'own'
uses: act/common/utils/chown@master
with:
file: ${{ inputs.artifactsDir }}
- name: "Copy artifacts"
if: inputs.artifactMode == 'copy'
uses: act/common/docker/docker-cp@master
with:
recreateVolume: true
volume: ${{inputs.artifactsVolume }}
fromPath: ${{ inputs.artifactsDir }}/.

View File

@@ -0,0 +1,58 @@
name: unity-default
description: "Run a Unity command using defaults loaded from environment variables."
inputs:
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
default: ${{ env.UNITY_PLATFORM }}
email:
description: "Unity email."
required: true
default: ${{ env.UNITY_USERNAME }}
password:
description: "Unity password."
required: true
default: ${{ env.UNITY_PASSWORD }}
command:
description: "Unity command to run."
required: false
unityBuilder:
description: "Whether or not to use the UnityBuilder instead of a Unity command."
required: false
buildDir:
description: "Where the built application ends up."
required: false
default: ${{ env.BUILD_DIR || 'build' }}
cacheVolume:
description: "Name of the volume to cache the Library folder to."
required: false
artifactsVolume:
description: "Name of the volume to copy the artifacts to."
required: true
default: ${{ env.ARTIFACTS_VOLUME }}
noGraphics:
description: "Whether or not to use the graphics device when running Unity."
required: false
default: ${{ env.NO_GRAPHICS || 'true' }}
artifactsDir:
description: "Name of the directory to copy the artifacts from."
required: true
default: artifacts
zipName:
description: "Name of the resulting zip file."
required: false
runs:
using: "composite"
steps:
- uses: act/unity/unity-composite@master
with:
platform: ${{ inputs.platform }}
email: ${{ inputs.email }}
password: ${{ inputs.password }}
command: ${{ inputs.command }}
unityBuilder: ${{ inputs.unityBuilder }}
buildDir: ${{ inputs.buildDir }}
artifactsDir: ${{ inputs.artifactsDir }}
cacheVolume: ${{ inputs.cacheVolume }}
zipName: ${{ inputs.zipName }}
noGraphics: ${{ inputs.noGraphics }}

View File

@@ -0,0 +1,23 @@
name: unity-get-buildtarget
description: "Get the correct Unity build target from a provided platform."
inputs:
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
outputs:
buildTarget:
description: "Unity Build Target."
value: ${{ steps.getTarget.outputs.buildTarget }}
buildArg:
description: "Unity Build Argument."
value: ${{ steps.getTarget.outputs.buildArg }}
runs:
using: "composite"
steps:
- name: "Get Unity Build Target."
id: getTarget
run: |
#Choose the correct buildTarget: https://docs.unity3d.com/Manual/EditorCommandLineArguments.html
bash ${{ github.action_path }}/get_target.sh "${{ inputs.platform }}"
shell: bash

View File

@@ -0,0 +1,38 @@
#!/bin/bash
UNITY_TARGET="$1"
TARGET=$(echo "$UNITY_TARGET" | awk '{print tolower($0)}')
BUILD_ARG=""
case $TARGET in
"windows")
UNITY_TARGET=Win64
BUILD_ARG=-buildWindows64Player
;;
"windows32bit")
UNITY_TARGET=Win
BUILD_ARG=-buildWindowsPlayer
;;
"mac")
UNITY_TARGET=OSXUniversal
BUILD_ARG=-buildOSXUniversalPlayer
;;
"ios")
UNITY_TARGET=iOS
;;
"linux")
UNITY_TARGET=Linux64
BUILD_ARG=-buildLinux64Player
;;
"android")
UNITY_TARGET=Android
;;
"webgl")
UNITY_TARGET=WebGL
;;
*)
echo "Invalid target. Valid options are: Windows, Windows32bit, Mac, iOS, Linux, Android, WebGL"
;;
esac
echo "buildTarget=$UNITY_TARGET" >> "$GITHUB_OUTPUT"
echo "buildArg=$BUILD_ARG" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,23 @@
name: unity-get-container
description: "Get the correct Unity docker container from a provided platform."
inputs:
version:
description: "Unity Version."
required: true
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
outputs:
container:
description: "Unity Docker Container"
value: ${{ steps.getContainer.outputs.container }}
runs:
using: "composite"
steps:
- name: "Get Unity Docker Container."
id: getContainer
run: |
#Choose the appropriate container from: https://hub.docker.com/r/unityci/editor
bash ${{ github.action_path }}/get_container.sh "${{ inputs.platform }}" "${{ inputs.version }}"
shell: bash

View File

@@ -0,0 +1,37 @@
#!/bin/bash
# Choose the appropriate container from: https://hub.docker.com/r/unityci/editor
UNITY_TARGET="$1"
UNITY_VERSION="$2"
TARGET=$(echo "$UNITY_TARGET" | awk '{print tolower($0)}')
BUILD_ARG=""
case $TARGET in
"windows" | "windows32bit")
UNITY_TARGET=windows-mono-1
;;
"mac" | "osx")
UNITY_TARGET=mac-mono-1
;;
"ios")
UNITY_TARGET=ios-1
UNITY_VERSION=ubuntu-$UNITY_VERSION
;;
"linux")
UNITY_TARGET=base-1
UNITY_VERSION=ubuntu-$UNITY_VERSION
;;
"android")
UNITY_TARGET=android-1
UNITY_VERSION=ubuntu-$UNITY_VERSION
;;
"webgl")
UNITY_TARGET=webgl-1
UNITY_VERSION=ubuntu-$UNITY_VERSION
;;
*)
echo "Invalid target. Valid options are: Windows, Windows32bit, Mac, iOS, Linux, Android, WebGL"
;;
esac
CONTAINER=unityci/editor:$UNITY_VERSION-$UNITY_TARGET
echo "container=$CONTAINER" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,25 @@
name: unity-get-version
description: "Get the correct Unity version from a provided project."
inputs:
projectPath:
description: "Path to the Unity project."
required: true
default: "."
outputs:
projectVersion:
description: "Unity project version."
value: ${{ steps.getVersion.outputs.projectVersion }}
runs:
using: "composite"
steps:
- name: "Get Unity project version."
id: getVersion
run: |
VERSION_KEY="m_EditorVersion"
VERSION_FILE="ProjectSettings/ProjectVersion.txt"
VERSION_FILE_PATH="${{ inputs.projectPath }}/$VERSION_FILE"
VERSION=$(grep -w $VERSION_KEY $VERSION_FILE_PATH | cut -d ':' -f2 | xargs)
echo "projectVersion=$VERSION" >> "$GITHUB_OUTPUT"
shell: bash

View File

@@ -0,0 +1,105 @@
name: unity-project-cached
description: "Run a Unity command using a project's version and a build target. Cache the library folder."
inputs:
projectPath:
description: "Path to the Unity project."
required: true
default: "."
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
serial:
description: "Unity license serial number."
required: true
email:
description: "Unity email."
required: true
password:
description: "Unity password."
required: true
executeMethod:
description: "Unity method to call."
required: false
command:
description: "Additional unity commands."
required: false
buildOnCacheHit:
description: "Whether or not to build if a cache was found. Default: true"
required: false
default: "true"
sshPublicKey:
description: "Public SSH key to use for git package restoration."
required: false
sshPrivateKey:
description: "Private SSH key to use for git package restoration."
required: false
cacheSuffix:
description: "Suffix or hash to use for the cache key."
required: false
default: ${{ github.sha }}
cachePrefix:
description: "Prefix to use for the cache key."
required: false
default: unity-library
releaseBranch:
description: "Release name to use for the middle of the cache key if an exact release match was not found."
required: false
default: release
cachePath:
description: "Cache path. Default: Library"
required: false
default: Library
outputs:
cacheChanged:
description: "Whether or not the cache was changed."
value: ${{ steps.check-cache.outputs.cache-hit != 'true' }}
runs:
using: "composite"
steps:
- name: "Get full cache key and build command."
id: command
run: |
# Get the full cache id.
echo "key=${{ inputs.cachePrefix }}-${{ github.ref_name }}-${{ inputs.cacheSuffix }}" >> "$GITHUB_OUTPUT"
# Get the build command.
COMMAND="${{ inputs.command }}"
if [[ -n "${{ inputs.executeMethod }}" ]]; then
COMMAND="$COMMAND -executeMethod ${{ inputs.executeMethod }}"
fi
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Check if cache exists."
if: ${{ !env.ACT }}
id: check-cache
uses: actions/cache/restore@v3
with:
path: ${{ inputs.cachePath }}
key: ${{ steps.command.outputs.key }}
lookup-only: true
- name: "Restore Library from Cache."
if: ${{ !env.ACT && ( inputs.buildOnCacheHit == 'true' || steps.check-cache.outputs.cache-hit != 'true' ) }}
uses: actions/cache/restore@v3
with:
path: ${{ inputs.cachePath }}
key: ${{ steps.command.outputs.key }}
restore-keys: |
${{ inputs.cachePrefix }}-${{ github.ref_name }}
${{ inputs.cachePrefix }}-${{ inputs.releaseBranch }}
${{ inputs.cachePrefix }}
- name: "Build project."
if: ${{ inputs.buildOnCacheHit == 'true' || steps.check-cache.outputs.cache-hit != 'true' }}
uses: act/common/unity/unity-project@master
with:
platform: ${{ inputs.platform }}
serial: ${{ inputs.serial }}
email: ${{ inputs.email }}
password: ${{ inputs.password }}
sshPublicKey: ${{ inputs.sshPublicKey }}
sshPrivateKey: ${{ inputs.sshPrivateKey }}
command: ${{ steps.command.outputs.command }}
- name: "Upload Library to Cache."
if: ${{ !env.ACT && steps.check-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v3
with:
path: ${{ inputs.cachePath }}
key: ${{ steps.command.outputs.key }}

View File

@@ -0,0 +1,74 @@
name: unity-project
description: "Run a Unity command using a project's version and a build target."
inputs:
projectPath:
description: "Path to the Unity project."
required: true
default: "."
platform:
description: "Unity Platform. Options: windows, windows32bit, mac, linux, android"
required: true
serial:
description: "Unity license serial number. Or 'personal' for a personal license."
required: true
default: personal
email:
description: "Unity email."
required: true
password:
description: "Unity password."
required: true
command:
description: "Unity command to run."
required: false
unityBuilder:
description: "Whether or not to use the UnityBuilder instead of a Unity command."
required: false
noGraphics:
description: "Whether or not to use the graphics device when running Unity."
required: false
default: "true"
cacheVolume:
description: "Name of the volume to cache the Library folder to."
required: false
removeContainer:
description: "Remove the mock container after building."
required: false
default: "false"
runs:
using: "composite"
steps:
- name: "Get Unity Version."
id: getVersion
uses: act/unity/unity-get-version@master
with:
projectPath: ${{ inputs.projectPath }}
- name: "Get Unity buildTarget."
id: getTarget
uses: act/unity/unity-get-buildtarget@master
with:
platform: ${{ inputs.platform }}
- name: "Restore the cached Library folder."
if: inputs.cacheVolume != null
uses: act/common/docker/docker-cp@master
with:
volume: ${{ inputs.cacheVolume }}
toPath: .
- name: "Run Unity command."
uses: act/unity/unity-command@master
with:
platform: ${{ inputs.platform }}
version: ${{ steps.getVersion.outputs.projectVersion }}
serial: ${{ inputs.serial }}
email: ${{ inputs.email }}
password: ${{ inputs.password }}
command: -projectPath ${{ inputs.projectPath }} -buildTarget ${{ steps.getTarget.outputs.buildTarget }} ${{ inputs.command }}
removeContainer: ${{ inputs.removeContainer }}
noGraphics: ${{ inputs.noGraphics }}
- name: "Cache the Library folder."
if: inputs.cacheVolume != null
uses: act/common/docker/docker-cp@master
with:
recreateVolume: true
volume: ${{ inputs.cacheVolume }}
fromPath: Library

29
unity/unity/action.yaml Normal file
View File

@@ -0,0 +1,29 @@
name: unity
description: "Register Unity with the provided license and run a Unity command."
inputs:
serial:
description: "Unity license serial number. Or 'personal' for a personal license. Or 'activated' to skip activation."
required: true
default: personal
email:
description: "Unity email."
required: true
password:
description: "Unity password."
required: true
command:
description: "Unity command to run."
required: false
unityBuilder:
description: "Whether or not to use the UnityBuilder instead of a Unity command."
required: false
runs:
using: docker
#This is a base "mock" image which is replaced by the correct image in the "unity-command" action at runtime.
image: docker://unityci/base:latest
args:
- ${{ inputs.serial }}
- ${{ inputs.email }}
- ${{ inputs.password }}
- ${{ inputs.command }}
- ${{ inputs.unityBuilder }}

View File

@@ -29,8 +29,8 @@ runs:
echo $USER_UID:$USER_GID echo $USER_UID:$USER_GID
echo "::set-output name=uid::$USER_UID" echo "uid=$USER_UID" >> "$GITHUB_OUTPUT"
echo "::set-output name=gid::$USER_GID" echo "gid=$USER_GID" >> "$GITHUB_OUTPUT"
shell: bash shell: bash
- name: "Take ownership of output." - name: "Take ownership of output."
uses: act/common/distros/busybox@master uses: act/common/distros/busybox@master

View File

@@ -0,0 +1,49 @@
name: compare-files
description: "Compare the output of a command to an expected value."
inputs:
expected:
description: "Expected output file."
required: true
expectedPattern:
description: "Optional pattern to match files in the expected directory."
required: false
actual:
description: "Actual output file."
required: true
actualPattern:
description: "Optional pattern to match files in the actual directory."
required: false
exitOnFail:
description: "Should the program exit on a failure."
required: true
default: "true"
outputs:
success:
description: "The result of the comparison."
value: ${{ steps.compare.outputs.success }}
runs:
using: "composite"
steps:
- name: "Read files."
id: read
run: |
LHS_NUSPEC=$(cat "${{ inputs.expected }}"${{ inputs.expectedPattern }})
RHS_NUSPEC=$(cat "${{ inputs.actual }}"${{ inputs.actualPattern }})
if [[ -n "$LHS_NUSPEC" ]]; then
echo "lhs<<EOF" >> "$GITHUB_OUTPUT"
echo "$LHS_NUSPEC" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
if [[ -n "$RHS_NUSPEC" ]]; then
echo "rhs<<EOF" >> "$GITHUB_OUTPUT"
echo "$RHS_NUSPEC" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
shell: bash
- name: "Build matrix from yaml."
uses: act/common/utils/compare@master
with:
expected: ${{ steps.read.outputs.lhs }}
actual: ${{ steps.read.outputs.rhs }}
exitOnFail: ${{ inputs.exitOnFail }}

View File

@@ -0,0 +1,99 @@
name: compare-nupkg
description: "Compare the contents of a nupkg file to an expected value."
inputs:
lhs:
description: "Left hand side nupkg."
required: true
rhs:
description: "Right hand side nupkg."
required: true
compareNuspec:
description: "Whether or not to compare the .nuspec file when comparing versions."
required: true
default: "false"
exitOnFail:
description: "Should the program exit on a failure."
required: true
default: "false"
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
outputs:
success:
description: "The result of the comparison."
value: ${{ steps.compare.outputs.success == 'true' && ( inputs.compareNuspec == 'false' || steps.compare-nuspec.outputs.success == 'true' ) }}
runs:
using: "composite"
steps:
- name: "Make temporary directory for lhs extraction"
id: mktemp-lhs
uses: act/common/utils/mktemp@master
with:
outputType: dir
tmpDir: ${{ inputs.tmpDir }}
- name: "Make temporary directory for rhs extraction"
id: mktemp-rhs
uses: act/common/utils/mktemp@master
with:
outputType: dir
tmpDir: ${{ inputs.tmpDir }}
- name: "Extract lhs."
uses: act/common/utils/extract@master
with:
file: ${{ inputs.lhs }}
outputDir: ${{ steps.mktemp-lhs.outputs.tmp }}
- name: "Extract rhs."
uses: act/common/utils/extract@master
with:
file: ${{ inputs.rhs }}
outputDir: ${{ steps.mktemp-rhs.outputs.tmp }}
- name: "Disassemble lhs dlls."
uses: act/common/mono/ikdasm-files@master
with:
directory: ${{ steps.mktemp-lhs.outputs.tmp }}/lib
deleteAssemblies: true
removeComments: true
- name: "Disassemble rhs dlls."
uses: act/common/mono/ikdasm-files@master
with:
directory: ${{ steps.mktemp-rhs.outputs.tmp }}/lib
deleteAssemblies: true
removeComments: true
- name: "Get shasum for lhs."
id: lhs-shasum
uses: act/common/utils/shasum-files@master
with:
directory: ${{ steps.mktemp-lhs.outputs.tmp }}/lib
pattern: "*"
- name: "Get shasum for rhs."
id: rhs-shasum
uses: act/common/utils/shasum-files@master
with:
directory: ${{ steps.mktemp-rhs.outputs.tmp }}/lib
pattern: "*"
- name: "Compare lhs and rhs."
id: compare
uses: act/common/utils/compare@master
with:
expected: ${{ steps.lhs-shasum.outputs.sums }}
actual: ${{ steps.rhs-shasum.outputs.sums }}
exitOnFail: ${{ inputs.exitOnFail }}
#TODO: Use a yq expression to remove the git sha and version before comparing.
- name: "Compare nuspec files."
id: compare-nuspec
if: ${{ inputs.compareNuspec == 'true' }}
uses: act/common/utils/compare-files@master
with:
expected: ${{ steps.mktemp-lhs.outputs.tmp }}
expectedPattern: /*.nuspec
actual: ${{ steps.mktemp-rhs.outputs.tmp }}
actualPattern: /*.nuspec
exitOnFail: ${{ inputs.exitOnFail }}
- name: "Take ownership of the artifacts."
uses: act/common/utils/chown@master
with:
file: ${{ inputs.tmpDir }}
- name: "Remove temporary files."
run: rm -rf "${{ inputs.tmpDir }}"
shell: bash

44
utils/compare/action.yaml Normal file
View File

@@ -0,0 +1,44 @@
name: compare
description: "Compare the output of a command to an expected value."
inputs:
expected:
description: "Expected output."
required: false
actual:
description: "Actual output."
required: true
exitOnFail:
description: "Should the program exit on a failure."
required: true
default: "true"
outputs:
success:
description: "The result of the comparison."
value: ${{ steps.compare.outputs.success }}
runs:
using: "composite"
steps:
- name: "Compare input and output"
id: compare
run: |
EXPECTED=$(cat <<EOF
${{ inputs.expected }}
EOF
)
ACTUAL=$(cat <<EOF
${{ inputs.actual }}
EOF
)
if [[ "$EXPECTED" == "$ACTUAL" ]]; then
echo "success=true" >> "$GITHUB_OUTPUT"
else
echo "success=false" >> "$GITHUB_OUTPUT"
if [[ "${{ inputs.exitOnFail }}" == "true" ]]; then
echo EXPECTED: "$EXPECTED"
echo --------------------------------
echo ACTUAL: "$ACTUAL"
exit 1
fi
fi
shell: bash

View File

@@ -5,4 +5,5 @@ if [[ -z "$OUTPUT_FILE" ]]; then
OUTPUT_FILE="$(basename $URL)" OUTPUT_FILE="$(basename $URL)"
fi fi
wget $URL -O "$OUTPUT_FILE" wget $URL -O "$OUTPUT_FILE"
echo "::set-output name=file::$OUTPUT_FILE"
echo "file=$OUTPUT_FILE" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,25 @@
#This is an example of a possible way to Unit Test a single action.
name: "Run unit tests."
on: workflow_call
jobs:
run-tests:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- name: "Run Test"
id: test
uses: ./.
env:
TEST_VAR: Hello, world!
with:
input: |
And I say:
"$TEST_VAR"
- name: "Verify output."
uses: act/common/utils/compare@master
with:
expected: |
And I say:
"Hello, world!"
actual: |
${{ steps.test.outputs.result }}

View File

@@ -0,0 +1,31 @@
name: envsubst
description: "Substitute environment variables in the given input."
inputs:
input:
description: "Input to substitute."
required: false
tmpDir:
description: "Temporary directory. Default: _tmp"
required: true
default: _tmp
outputs:
result:
description: "The result of the substitution."
value: ${{ steps.envsubst.outputs.console }}
runs:
using: "composite"
steps:
- name: "Make temporary file of input."
id: mktmp
uses: act/common/utils/mktemp@master
with:
input: ${{ inputs.input }}
tmpDir: ${{ inputs.tmpDir }}
- name: "Download file."
id: envsubst
uses: act/common/distros/rockylinux@master
with:
args: envsubst < ${{ steps.mktmp.outputs.tmp }}
- name: "Remove temporary files."
run: rm -rf "${{ inputs.tmpDir }}"
shell: bash

View File

@@ -27,9 +27,9 @@ runs:
COMMAND="unzip ${{ inputs.prefixArgs }} -o ${{ inputs.file }} ${{ inputs.additionalArgs }}" COMMAND="unzip ${{ inputs.prefixArgs }} -o ${{ inputs.file }} ${{ inputs.additionalArgs }}"
OUTPUT_DIR="${{ inputs.outputDir }}" OUTPUT_DIR="${{ inputs.outputDir }}"
if [[ -n "$OUTPUT_DIR" ]]; then if [[ -n "$OUTPUT_DIR" ]]; then
COMMAND="$COMMAND" -d "$OUTPUT_DIR" COMMAND="$COMMAND -d \"$OUTPUT_DIR\""
fi fi
echo "::set-output name=command::$COMMAND" echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
shell: bash shell: bash
- name: "Convert file." - name: "Convert file."
id: convert id: convert
@@ -39,7 +39,8 @@ runs:
- name: "Delete source." - name: "Delete source."
run: | run: |
if [[ ${{ inputs.deleteSource }} != "true" ]]; then if [[ ${{ inputs.deleteSource }} != "true" ]]; then
return exit 0
fi fi
rm ${{ inputs.file }} rm ${{ inputs.file }}
shell: bash shell: bash

View File

@@ -0,0 +1,44 @@
name: get-latest-version
description: "Get the latest version of a package."
inputs:
versions:
description: "Newline-seperated list of package versions."
required: true
filter:
description: "String to filter by."
required: false
filterIsExpression:
description: "Is the first filter a Regular Expression? Values: true, false."
required: false
default: "false"
stripPrerelease:
description: "Whether or not to strip prerelease versions. Values: true, false."
required: false
default: "false"
outputs:
version:
description: "The latest version of the specified package."
value: ${{ steps.parse.outputs.version }}
runs:
using: "composite"
steps:
- name: "Get latest package."
id: parse
run: |
VERSIONS="${{ inputs.versions }}"
# Filter versions, sort them, and get the latest one
if [[ "${{ inputs.filterIsExpression }}" == "true" ]]; then
EXPRESSION_FLAG="-E"
fi
if [[ "${{ inputs.stripPrerelease }}" == "true" ]]; then
VERSIONS=$(echo "$VERSIONS" | grep -E "^(v)?[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$")
fi
RESULT=$(echo "$VERSIONS" | grep $EXPRESSION_FLAG "${{ inputs.filter }}" || echo "error")
VERSION=$(echo "$RESULT" | sort -rV | head -1)
if [[ "$RESULT" != "error" ]]; then
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
fi
# No error if no versions found.
shell: bash

View File

@@ -0,0 +1,29 @@
name: inputtype
description: "Determine whether the input is a file, directory, or raw input."
inputs:
input:
description: "Input contents."
required: true
outputs:
type:
description: "Whether the input is a file, dir (directory), or raw input."
value: ${{ steps.gettype.outputs.type }}
runs:
using: "composite"
steps:
- name: "Make the temporary file."
id: gettype
run: |
#Store in a heredoc to account for quotes.
INPUT=$(cat <<EOF
${{ inputs.input }}
EOF
)
TYPE="raw"
if [[ -f "$INPUT" ]]; then
TYPE="file"
elif [[ -d "$INPUT" ]]; then
TYPE="dir"
fi
echo "type=$TYPE" >> "$GITHUB_OUTPUT"
shell: bash

55
utils/mktemp/action.yaml Normal file
View File

@@ -0,0 +1,55 @@
name: mktemp
description: "Make a temporary file or directory with the specified contents."
inputs:
input:
description: "Contents of the temporary file or directory."
required: false
default: ""
inputType:
description: "How the input should be parsed. Options: raw, file, dir, expression, auto"
required: false
default: auto
outputType:
description: "How the input should be output. Options: file, dir, auto"
required: false
default: auto
transferType:
description: "How the input should be transferred. Options: copy, move"
required: false
default: copy
tmpDir:
description: "Temporary directory. Default: /tmp"
required: true
default: /tmp
additionalArgs:
description: "Additional arguments to pass in."
required: false
outputs:
tmp:
description: "The name of the temporary file or directory."
value: ${{ steps.mktemp.outputs.tmp }}
runs:
using: "composite"
steps:
- name: "Get the proper input type."
if: ${{ inputs.inputType == 'auto' }}
id: getinputtype
uses: act/common/utils/inputtype@master
with:
input: ${{ inputs.input }}
- name: "Make the temporary file."
id: mktemp
run: |
INPUT_TYPE="${{ inputs.inputType }}"
if [[ $INPUT_TYPE == 'auto' ]]; then
INPUT_TYPE="${{ steps.getinputtype.outputs.type }}"
fi
#Store in a heredoc to account for quotes.
INPUT=$(cat <<EOF
${{ inputs.input }}
EOF
)
bash ${{ github.action_path }}/make_temp.sh "$INPUT" "$INPUT_TYPE" "${{ inputs.outputType }}" "${{ inputs.transferType }}" "${{ inputs.tmpDir }}" "${{ inputs.additionalArgs }}"
shell: bash

54
utils/mktemp/make_temp.sh Normal file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
INPUT="$1"
INPUT_TYPE="$2"
OUTPUT_TYPE="$3"
TRANSFER_TYPE="$4"
TMP_DIR="$5"
MKTEMP_ARGS="$6"
# match up the output type to the input type.
if [[ $OUTPUT_TYPE == 'auto' ]]; then
if [[ $INPUT_TYPE == 'raw' ]]; then
OUTPUT_TYPE="file"
elif [[ $INPUT_TYPE == 'expression' ]]; then
OUTPUT_TYPE="dir"
else
OUTPUT_TYPE="$INPUT_TYPE"
fi
fi
if [[ $INPUT_TYPE == 'raw' && $OUTPUT_TYPE == 'dir' && -n "$INPUT" ]]; then
echo "Can't output raw input to a temporary directory."
exit 1
fi
if [[ $OUTPUT_TYPE == "dir" ]]; then
MKTEMP_ARGS="-d $MKTEMP_ARGS"
fi
mkdir -p "$TMP_DIR"
TMP=$(mktemp -p "$TMP_DIR" $MKTEMP_ARGS)
echo "tmp=$TMP" >> "$GITHUB_OUTPUT"
if [[ -z "$INPUT" ]]; then
exit 0
fi
TRANSFER_COMMAND="cp -r"
if [[ $TRANSFER_TYPE == 'move' ]]; then
TRANSFER_COMMAND="mv"
fi
if [[ $INPUT_TYPE == 'raw' ]]; then
echo "$INPUT" > "$TMP"
elif [[ $OUTPUT_TYPE == 'file' ]]; then
$TRANSFER_COMMAND "$INPUT" "$TMP"
elif [[ $OUTPUT_TYPE == 'dir' ]]; then
if [[ $INPUT_TYPE == "expression" ]]; then
$TRANSFER_COMMAND $INPUT "$TMP"
else
$TRANSFER_COMMAND "$INPUT" "$TMP"
fi
fi

View File

@@ -0,0 +1,28 @@
name: shasum-files
description: "Output the shasum of files in a directory matching a pattern."
inputs:
directory:
description: "Directory to search."
required: true
default: '.'
pattern:
description: "Pattern of files to search for."
required: true
default: '*'
outputs:
sums:
description: "The sums of the files matching the pattern."
value: ${{ steps.sums.outputs.sums }}
runs:
using: "composite"
steps:
- name: "Get sums of files matching the pattern"
id: sums
run: |
OUTPUT=$(bash ${{ github.action_path }}/get_sums.sh "${{ inputs.directory }}" "${{ inputs.pattern }}")
if [[ -n "$OUTPUT" ]]; then
echo "sums<<EOF" >> "$GITHUB_OUTPUT"
echo "$OUTPUT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
fi
shell: bash

View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Get the directory and pattern as arguments
DIR=$1
PATTERN=$2
find "$DIR" -type f -name "$PATTERN" -print0 | while IFS= read -r -d '' file; do
# compute the sha256 hash of the file using sha256sum command
HASH=$(sha256sum "$file" | cut -d " " -f1)
NAME=$(basename "$file")
# print the file name and hash to a temporary file
echo "$NAME: $HASH"
done

View File

@@ -0,0 +1,47 @@
name: urlencode
description: "Encode or decode the input string as a url."
inputs:
input:
description: "Input to encode/decode."
required: true
mild:
description: "Do a mild conversion."
required: false
default: "false"
decode:
description: "Whether or not to decode instead of encode."
required: true
default: "false"
outputs:
result:
description: "The url-encoded or decoded string."
value: ${{ steps.url.outputs.console }}
runs:
using: "composite"
steps:
- name: "Build the command."
id: command
run: |
COMMAND="urlencode"
DECODE="${{ inputs.decode }}"
if [[ "$DECODE" == "true" ]]; then
COMMAND="$COMMAND -d"
fi
MILD="${{ inputs.mild }}"
if [[ "$MILD" == "true" ]]; then
if [[ "$DECODE" == "true" ]]; then
echo "Cannot perform url decoding in mild mode."
exit 1
fi
COMMAND="$COMMAND -m"
fi
echo "command=$COMMAND" >> "$GITHUB_OUTPUT"
shell: bash
- name: "Encode/decode the input."
id: url
uses: act/common/distros/debian@master
with:
args: ${{ steps.command.outputs.command }} "${{ inputs.input }}"

18
utils/uuid/action.yaml Normal file
View File

@@ -0,0 +1,18 @@
name: uuid
description: "Download a file from a URL."
inputs:
additionalArgs:
description: "Additional arguments to pass in."
required: false
outputs:
uuid:
description: "The unique identifier output."
value: ${{ steps.uuid.outputs.console }}
runs:
using: "composite"
steps:
- name: "Download file."
id: uuid
uses: act/common/distros/rockylinux@master
with:
args: uuid ${{ inputs.additionalArgs }}

View File

@@ -0,0 +1,57 @@
name: version-increment-branch
description: "Get the latest and next version of a package from a NuGet repository based on the current branch and merge target."
inputs:
version:
description: "The version to increment."
required: false
outputs:
nextVersion:
description: "The next version of the package, based on the current branch and merge target."
value: ${{ steps.increment.outputs.nextVersion }}
baseVersion:
description: "Base of the branch-defined version."
value: ${{ steps.branch.outputs.baseVersion }}
majorMinorPatchVersion:
description: "Major.Minor.Patch of the latest version."
value: ${{ steps.branch.outputs.majorMinorPatchVersion }}
runs:
using: "composite"
steps:
- name: "Get latest non-pre-release NuGet package version."
id: parse
uses: act/common/utils/version-parse@master
with:
version: ${{ inputs.version }}
- name: "Build the next version with the given repository information."
id: branch
run: |
EVENT_NAME="${{ github.event_name }}"
HEAD="${{ github.head_ref || github.ref_name }}"
BASE="${{ github.base_ref || github.ref_name }}"
PR_NUMBER="${{ github.event.number || '-1' }}"
MAJOR="${{ steps.parse.outputs.major || '0' }}"
MINOR="${{ steps.parse.outputs.minor || '0' }}"
PATCH="${{ steps.parse.outputs.patch || '0' }}"
LAST_MMP_VERSION="$MAJOR.$MINOR.$PATCH"
REVISION="${{ steps.parse.outputs.revision || '0' }}"
bash ${{ github.action_path }}/get_next_version.sh "$EVENT_NAME" "$HEAD" "$BASE" "$PR_NUMBER" "$LAST_MMP_VERSION" "$REVISION"
shell: bash
- name: "Parse the version to increment."
id: parseNext
uses: act/common/utils/version-parse@master
with:
version: ${{ steps.branch.outputs.currentVersion }}
- name: "Get next version."
id: increment
uses: act/common/utils/version-increment@master
with:
incrementMode: revision
major: ${{ steps.parseNext.outputs.major }}
minor: ${{ steps.parseNext.outputs.minor }}
patch: ${{ steps.parseNext.outputs.patch }}
revision: ${{ steps.parseNext.outputs.revision }}
suffix: ${{ steps.parseNext.outputs.suffix }}
metadata: ${{ steps.parseNext.outputs.metadata }}

View File

@@ -0,0 +1,30 @@
#!/bin/bash
function compare_versions
{
# Check if two arguments are given
if [ $# -ne 2 ]; then
echo "Please provide two version numbers to compare"
return 1
fi
# Assign arguments to local variables
local ver1=$1
local ver2=$2
# Remove dots and pad with zeros
ver1=${ver1//./}
ver2=${ver2//./}
printf -v ver1 "%-4s" "$ver1"
printf -v ver2 "%-4s" "$ver2"
ver1=${ver1// /0}
ver2=${ver2// /0}
# Compare as integers and return result
if [ $ver1 -lt $ver2 ]; then
return -1
elif [ $ver1 -gt $ver2 ]; then
return 1
else
return 0
fi
}

View File

@@ -0,0 +1,52 @@
#!/bin/bash
FILE_PATH=$(readlink -f "$BASH_SOURCE")
FILE_DIR=$(dirname "$FILE_PATH")
source "$FILE_DIR/compare_versions.sh"
EVENT_NAME="$1"
HEAD="$2"
BASE="$3"
PR_NUMBER="$4"
LATEST_MMP_VERSION="$5" # Latest major.minor.patch version.
LATEST_REVISION="${6:-0}"
if [[ ! -f "$GITHUB_OUTPUT" ]]; then
# Write to stdout if the output file doesn't exist.
GITHUB_OUTPUT="/dev/fd/1"
fi
BASE_VERSION=$(echo "$BASE" | cut -d '/' -sf 2 | xargs)
# Remove the first v in the version if it has onem as well as invalid characters.
BASE_VERSION="${BASE_VERSION#v}"
# Convert the base to a valid semver version. Anything not alphanumeric or a - or ..
BASE_VERSION="${BASE_VERSION//[^a-z0-9\-\.]/-}"
if [[ -z "$BASE_VERSION" ]]; then
# Just use the latest version as a base if the release branch has no possible versions.
BASE_VERSION="$LATEST_MMP_VERSION"
fi
echo "majorMinorPatchVersion=$BASE_VERSION" >> "$GITHUB_OUTPUT"
# Convert the head to a valid semver patch version. Anything not alphanumeric or a -.
HEAD="${HEAD//[^a-z0-9\-]/-}"
compare_versions "$BASE_VERSION" "$LATEST_MMP_VERSION"
if [[ $? == 1 ]]; then
# If the base version is greater than the latest version, then set the increment mode to 'patch'
LATEST_REVISION=0
fi
if [[ "$EVENT_NAME" == "pull_request" ]]; then
# Use the branch name as a prerelease version and increment the revision.
BASE_VERSION="$BASE_VERSION-$PR_NUMBER.$HEAD"
CURRENT_VERSION="$BASE_VERSION.$LATEST_REVISION"
elif [[ "$EVENT_NAME" != "push" && "$EVENT_NAME" != "workflow_dispatch" ]]; then
echo "Invalid event name to attempt to push a package on: $EVENT_NAME"
exit 1
fi
CURRENT_VERSION="$BASE_VERSION.$LATEST_REVISION"
echo "baseVersion=$BASE_VERSION" >> "$GITHUB_OUTPUT"
echo "currentVersion=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,59 @@
name: version-increment
description: "Increment a semantic version 2.0."
inputs:
incrementMode:
description: "The mode to increment by. Options: 'default', 'major', 'minor', 'patch', 'revision'"
required: true
default: default
gitShaMetadata:
description: "Whether or not to update the git sha in the metadata."
required: false
default: "false"
major:
description: "The latest major version of the package."
required: false
minor:
description: "The latest minor version of the package."
required: false
patch:
description: "The latest patch version of the package."
required: false
revision:
description: "The latest patch revision version of the package. The suffix treated as a number seperated by a '.'"
required: false
suffix:
description: "The suffix of the package."
required: false
metadata:
description: "The metadata of the package."
required: false
outputs:
nextVersion:
description: "The next version of the package."
value: ${{ steps.parse.outputs.nextVersion }}
nextMajor:
description: "The next major version of the package."
value: ${{ steps.parse.outputs.nextMajor }}
nextMinor:
description: "The next minor version of the package."
value: ${{ steps.parse.outputs.nextMinor }}
nextPatch:
description: "The next patch version of the package."
value: ${{ steps.parse.outputs.nextPatch }}
nextRevision:
description: "The next patch revision version of the package."
value: ${{ steps.parse.outputs.nextRevision }}
nextSuffix:
description: "The next version of suffix of the package."
value: ${{ steps.parse.outputs.nextSuffix }}
nextMetadata:
description: "The next version of metadata of the package."
value: ${{ steps.parse.outputs.nextMetadata }}
runs:
using: "composite"
steps:
- name: "Get next version."
id: parse
run: |
bash ${{ github.action_path }}/increment_version.sh "${{ inputs.major }}" "${{ inputs.minor }}" "${{ inputs.patch }}" "${{ inputs.revision }}" "${{ inputs.suffix }}" "${{ inputs.metadata }}" "${{ inputs.incrementMode }}" "${{ inputs.gitShaMetadata }}"
shell: bash

View File

@@ -0,0 +1,67 @@
#!/bin/bash
MAJOR="$1"
MINOR="$2"
PATCH="$3"
REVISION="$4"
SUFFIX="$5"
METADATA="$6"
INCREMENT_MODE="${7:-default}"
GIT_SHA_METADATA="$8"
if [[ ! -f "$GITHUB_OUTPUT" ]]; then
# Write to stdout if the output file doesn't exist.
GITHUB_OUTPUT="/dev/fd/1"
fi
NEXT_MAJOR=$((MAJOR + 1))
NEXT_MINOR=$((MINOR + 1))
NEXT_PATCH=$((PATCH + 1))
NEXT_REVISION=$((REVISION + 1))
NEXT_SUFFIX="$SUFFIX"
NEXT_METADATA="$METADATA"
if [[ "$GIT_SHA_METADATA" == "true" ]]; then
NEXT_METADATA="$GITHUB_SHA"
fi
echo "nextMajor=$NEXT_MAJOR" >> "$GITHUB_OUTPUT"
echo "nextMinor=$NEXT_MINOR" >> "$GITHUB_OUTPUT"
echo "nextPatch=$NEXT_PATCH" >> "$GITHUB_OUTPUT"
echo "nextRevision=$NEXT_REVISION" >> "$GITHUB_OUTPUT"
echo "nextSuffix=$NEXT_SUFFIX" >> "$GITHUB_OUTPUT"
echo "nextMetadata=$NEXT_METADATA" >> "$GITHUB_OUTPUT"
# This script assumes that thre version numbers is the desired default format.
NEXT_VERSION="${MAJOR:-0}.${MINOR:-0}"
if [[ "$INCREMENT_MODE" == "default" ]]; then
if [[ -n "$REVISION" ]]; then
NEXT_VERSION="$NEXT_VERSION.${PATCH:-0}.$NEXT_REVISION"
elif [[ -n "$PATCH" ]]; then
NEXT_VERSION="$NEXT_VERSION.$NEXT_PATCH"
elif [[ -n "$MINOR" ]]; then
NEXT_VERSION="${MAJOR:-0}.$NEXT_MINOR.0"
else
NEXT_VERSION="$NEXT_MAJOR.0.0"
fi
elif [[ "$INCREMENT_MODE" == "major" ]]; then
NEXT_VERSION="$NEXT_MAJOR.0.0"
elif [[ "$INCREMENT_MODE" == "minor" ]]; then
NEXT_VERSION="${MAJOR:-0}.$NEXT_MINOR.0"
elif [[ "$INCREMENT_MODE" == "patch" ]]; then
NEXT_VERSION="${MAJOR:-0}.${MINOR:-0}.$NEXT_PATCH"
elif [[ "$INCREMENT_MODE" == "revision" ]]; then
NEXT_VERSION="${MAJOR:-0}.${MINOR:-0}.${PATCH:-0}.$NEXT_REVISION"
else
echo "Invalid increment mode: $INCREMENT_MODE"
exit 1
fi
if [[ -n "$NEXT_SUFFIX" ]]; then
NEXT_VERSION="$NEXT_VERSION-$NEXT_SUFFIX"
fi
if [[ -n "$NEXT_METADATA" ]]; then
NEXT_VERSION="$NEXT_VERSION+$NEXT_METADATA"
fi
echo "nextVersion=$NEXT_VERSION" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,38 @@
name: version-parse
description: "Parse a semantic version."
inputs:
version:
description: "The version to parse."
required: true
outputs:
version:
description: "The version of the package."
value: ${{ steps.parse.outputs.version }}
major:
description: "The major version of the package."
value: ${{ steps.parse.outputs.major }}
minor:
description: "The minor version of the package."
value: ${{ steps.parse.outputs.minor }}
patch:
description: "The patch version of the package."
value: ${{ steps.parse.outputs.patch }}
revision:
description: "The patch revision version of the package. The suffix treated as a number seperated by a '.'"
value: ${{ steps.parse.outputs.revision }}
metadata:
description: "The of the package."
value: ${{ steps.parse.outputs.metadata }}
suffix:
description: "The suffix of the package."
value: ${{ steps.parse.outputs.suffix }}
isPrerelease:
description: "Whether or not the package is a prerelease package."
value: ${{ steps.parse.outputs.isPrerelease }}
runs:
using: "composite"
steps:
- name: "Parse version."
id: parse
run: bash ${{ github.action_path }}/parse_version.sh "${{ inputs.version }}"
shell: bash

View File

@@ -0,0 +1,30 @@
#!/bin/bash
VERSION="$1"
if [[ ! -f "$GITHUB_OUTPUT" ]]; then
# Write to stdout if the output file doesn't exist.
GITHUB_OUTPUT="/dev/fd/1"
fi
IS_PRERELEASE=$(echo "$VERSION" | grep -c '-')
if [[ "$IS_PRERELEASE" == 0 ]]; then
IS_PRERELEASE=false
else
IS_PRERELEASE=true
fi
echo "isPrerelease=$IS_PRERELEASE" >> "$GITHUB_OUTPUT"
MAJOR=$(echo "$VERSION" | cut -d '.' -f 1 | cut -d '+' -f 1 | xargs printf %d 2> /dev/null)
MINOR=$(echo "$VERSION" | cut -d '.' -f 2 | cut -d '+' -f 1 | xargs printf %d 2> /dev/null)
PATCH=$(echo "$VERSION" | cut -d '.' -f 3 | cut -d '-' -f 1 | xargs | cut -d '+' -f 1 | xargs printf %d 2> /dev/null)
REVISION=$(echo "$VERSION" | cut -d '.' -f 4 | cut -d '-' -f 1 | cut -d '+' -f 1 | xargs printf %d 2> /dev/null)
SUFFIX=$(echo "$VERSION" | sed "s|^$MAJOR.$MINOR.$PATCH||" | sed "s|^.$REVISION||" | sed "s|^-||" | cut -d '+' -f 1 | xargs)
METADATA=$(echo "$VERSION" | cut -d '+' -sf 2 | xargs) # Empty if no delimeter '+' present.
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
echo "minor=$MINOR" >> "$GITHUB_OUTPUT"
echo "patch=$PATCH" >> "$GITHUB_OUTPUT"
echo "revision=$REVISION" >> "$GITHUB_OUTPUT"
echo "suffix=$SUFFIX" >> "$GITHUB_OUTPUT"
echo "metadata=$METADATA" >> "$GITHUB_OUTPUT"

Some files were not shown because too many files have changed in this diff Show More