Developer reference

Here is all you need to know to develop GitHub Actions with Quarkus GitHub Action.

Routing

Action methods

An action method is a method that is going to be executed when the GitHub Action is executed.

You can have several action methods, in which case they will be executed in no particular order.

You can also name your action methods to be able to trigger a specific method by passing an input to the action.

An action method is a method of a public class and is annotated with @io.quarkiverse.githubaction.Action:

public class MyAction {

    @Action
    void action() {
        // do something
    }
}

As explained above, you can have several action methods, and they can be in several classes:

public class MyAction1 {

    @Action
    void action1() {
        // do something
    }

    @Action
    void action2() {
        // do something
    }
}

public class MyAction2 {

    @Action
    void action3() {
        // do something
    }

    @Action
    void action4() {
        // do something
    }
}

When executing the action, action1(), action2(), action3(), and action4() will be executed in no particular order.

With this kind of setup, you can call your action with:

      - name: Run my action
        uses: my/action-github-repository@main
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

To call an action from a private repository, the action itself needs to be in a private repository as well (under the same organization or user).

For details on how to call the action, please see Run your action.

Named actions

It might be practical for you to develop one GitHub Action for several related purposes. Quarkus GitHub Action comes with a nice feature for that: named actions.

public class MyAction1 {

    @Action("action1")
    void action1() {
        // do something
    }

    @Action("action2")
    void action2() {
        // do something
    }
}

You can then specifically get action1() to run with:

      - name: Run my action
        uses: my/action-github-repository@main
        with:
          action: action1 (1)
          github-token: ${{ secrets.GITHUB_TOKEN }}
1 action is a special input that is used to route the action to the named action method, here action1.

Parameter injection

Most of the other features of Quarkus GitHub Action are handled via parameter injection: you can inject parameters of different types into your action methods, Quarkus GitHub Action will automatically pass the parameters, properly initialized.

You can of course pass several of the following parameter types to the action methods.

Inputs

Inputs are values that are passed from the GitHub workflow to the GitHub Action, for instance with the following step:

      - name: Run my action
        uses: my/action-github-repository@main
        with:
          my-input: "My value"
          github-token: ${{ secrets.GITHUB_TOKEN }}

It is required to declare the inputs in the action.yml descriptor:

name: 'My Action'
description: 'Description of my action'
inputs:
  my-input:
    description: 'My input'
    required: true (1)
    default: 'My default value' (2)

# ... rest of the descriptor ...
1 An input can be required or optional (optional by default).
2 An input can have a default value.

Getting the my-input input from an action method is easy:

    @Action
    void action(Inputs inputs) {
        String myInput = inputs.getRequired("my-input");
    }

Inputs offers all sorts of utility methods such as get(String) which returns an Optional, getRequired(String) which makes sure the input is provided, getBoolean(String), getLong(String), getInteger(String)…​

You can also get all the inputs as a Map<String, String> with all().

Contributions are welcome to add more utility methods to Inputs.

You can find more information about inputs in the GitHub Actions documentation.

Context

A GitHub action is executed within a context, which provides all sorts of information about the execution environment of the action.

To access the context, inject a Context instance into your action method:

    @Action
    void action(Context context) {
        String runnerOs = context.getRunnerOs(); (1)

        context.print(); (2)
    }
1 Get the GitHub Actions runner operating system.
2 Print all the available values. Useful to discover what is provided by the context.

Commands

GitHub Actions provides various commands which allows you to interact with the workflow run.

For instance, you can set output variables, attach a job summary…​

All these commands are made available through a io.quarkiverse.githubaction.Commands instance, that you can inject into your action methods.

Logging

While you can use standard Java logging, using Commands log facilities may be more practical as the logging appears in the job summary:

Logging in log
Logging in job summary

Commands exposes the debug(), notice(), warning(), and error() methods.

For debug(), see Enabling debug logging for more information about how to enable the debug output when your actions are executed.

Outputs

Outputs are an important part of GitHub Actions. They are used to export values from an action so that they can be consumed in further steps.

The first step in defining an output is to modify the action.yml descriptor to declare the output:

outputs:
  my-output:
    value: ${{ steps.action.outputs.my-output }}

This is required because we use a composite action. The output from the inner step needs to be mapped to an output of the action.

Next step is to actually produce the output in your action method:

    @Action
    void action(Commands commands) {
        commands.setOutput("my-output", "My value");
    }

You can produce several outputs.

And finally you can consume the output in another step of a GitHub Actions workflow:

    steps:
      - name: Run my action
        id: my-action
        uses: my/action-github-repository@main
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
      - name: Display output
        run: |
          echo "${{steps.my-action.outputs.my-output}}"

Job summary

A job summary is a Markdown content that you can attach to workflow run summary page. It can be used to provide an execution report for instance.

Adding a job summary is easy:

    @Action
    void action(Commands commands) {
        commands.jobSummary("# Markdown content"); (1)
        commands.appendJobSummary("Some additional content"); (2)
        commands.removeJobSummary(); (3)
    }
1 Set the job summary to # Markdown content.
2 Append Some additional content to a potentially preexisting job summary.
3 Remove the job summary. Not extremely useful but it is there just in case.

Other commands

There are several other commands available such as saveState, environmentVariable or systemPath.

Have a look at the Commands interface and Javadoc to learn more about them. The Javadoc contains pointers to the corresponding GitHub Actions documentation sections.

GitHub clients

One common use case of GitHub Actions is to perform calls on the GitHub REST or GraphQL APIs.

Quarkus GitHub Action has this use case covered and you can inject in your action methods:

Injecting a REST GitHub client
    @Action
    void action(GitHub gitHub) throws IOException {
        gitHub.getRepository("another/repository");
    }
Injecting a GraphQL client
    @Action
    void action(DynamicGraphQLClient graphqlClient) throws ExecutionException, InterruptedException {
        graphqlClient.executeSync("your GraphQL query");
    }

The clients are authenticated using the provided GitHub token.

Payloads

A GitHub workflow run is started when an event is triggered, and to this event corresponds a payload which contains all the information about the event.

Typically, when an issue is opened, you can obtain an issues payload. When a pull request is opened, you can obtain a pull_request payload.

Quarkus GitHub Action is able to parse the payload and inject it into an action method.

Payloads can also be used to restrict the use of an action to a particular event type, or to execute code that is specific to an event type.

A payload comes with an authenticated GitHub client, which makes it possible to access the GitHub REST API.

The following action method is executed any time an issues event is triggered (for instance when an issue is opened or edited):

    @Action
    void action(@Issue GHEventPayload.Issue issuePayload) throws IOException {
        GHIssue issue = issuePayload.getIssue();

        System.out.println("Repository: " + issue.getRepository().getFullName()); (1)
        System.out.println("Issue title: " + issue.getTitle());

        issue.comment("A new comment"); (2)
    }
1 Access some information from the payload.
2 Create a new comment in the issue.

Given you can have several action methods in the same GitHub Actions, it is possible to execute code for several event types.

You can restrict the action method to a particular action of the event type. The following action method is executed when a new issue is opened:

    @Action
    void action(@Issue.Opened GHEventPayload.Issue issuePayload) {
        System.out.println("Repository: " + issuePayload.getIssue().getRepository().getFullName());
        System.out.println("Issue title: " + issuePayload.getIssue().getTitle());
    }

You can find the list of all the supported event types in the Quarkus GitHub App documentation.

Config files

You can easily inject config files stored in the repository for which the action is run.

If the file is a YAML or JSON file, it can be automatically deserialized by Jackson.

If the file is a .txt file, it can be injected as a String. Text files can be used to inject templates.

For now, the file is read from the default branch of the repository (typically main).

If the path is relative, the file is searched in the .github directory. If the path is absolute, the file is searched from the root of the repository.

    @Action
    void action(@ConfigFile("example-config-file.yml") ConfigFileBean configFileBean) { (1)
        System.out.println("Value 1: " + configFileBean.value1);
        System.out.println("Value 2: " + configFileBean.value2);
    }

    public static class ConfigFileBean {

        public String value1;

        public String value2;
    }
1 Read .github/example-config-file.yml from the default branch of the repository and inject the values into ConfigFileBean via Jackson deserialization.

GHRepository

You can inject the current repository into any action method. This allows you to access the REST API for GitHub repositories.

This enables you to e.g.:

  • create / query issues

  • create / query pull requests

  • access workflows

  • and much more

@Action
void action(GHRepository repository) { (1)
    System.out.println(repository.getFullName());

    var issueBuilder = repository.createIssue("Issue Name"); (2)
    var pullRequest = repository.getPullRequest(42); (3)
    var workflows = repository.listWorkflows(); (4)
}
1 Inject the current repository
2 Create an issue
3 Retrieve a pull request
4 List all workflows

For a complete list of all possibilities and the concrete syntax see the Javadoc for GHRepository.

Debugging

If you need to debug the behavior of the Quarkus GitHub Action extension, you can enable debug logging by adding the following configuration property to your application.properties:

quarkus.log.category."io.quarkiverse.githubaction".level=DEBUG

Next steps