Setup GitHub Actions through a GitHub App
In this post I will explain how to setup GitHub Actions programmatically. Although libraries ilke kohsuhke make it easy to commit the workflow files to your repository, the preferred way of authenticating is discouraged for certain use cases. That’s why it might be worth thinking about using a GitHup App instead.
- Create your GitHub App by following the steps described at https://docs.github.com/en/free-pro-team@latest/developers/apps/creating-a-github-app
- It needs to have Read & Write access to the repository contents in order to be able to read and subsequently commit files
- Generate a private key as described at https://docs.github.com/en/free-pro-team@latest/developers/apps/authenticating-with-github-apps and download it
- Install the GitHub App to your organization or user. In case of choosing an organization you have to define the repositories the app should have access to.
- Note down the application’s id to generate a Json Web Token later on
- Convert the downloaded private key PEM file into a DER file, which is consumable by Java:
openssl pkcs8 -topk8 -inform PEM -outform DER -in myapp.2021-01-03.private-key.pem -out myapp.2021-01-03.private-key.der -nocrypt
- Generate a Json Web Token
String applicationId = "...."; SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); String keyFile = "...."; byte keyBytes = Files.toByteArray(new File(keyFile)); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory kf = KeyFactory.getInstance("RSA"); Key signingKey = kf.generatePrivate(spec); JwtBuilder builder = Jwts.builder() .setIssuedAt(now) .setIssuer(applicationId) .signWith(signingKey, signatureAlgorithm); // time to live of the token in milliseconds Long ttlMillis = 60000; long expMillis = nowMillis + ttlMillis; Date exp = new Date(expMillis); builder.setExpiration(exp); String jwtToken = builder.compact()
- Use it to create a so-called App Installation token
GitHub gitHubApp = new GitHubBuilder() .withJwtToken(jwtToken) .build(); String organisation = "...." GHAppInstallation appInstallation = gitHubApp .getApp() .getInstallationByOrganization(organisation); Map<String, GHPermissionType> permissions = new HashMap<>(); permissions.put("contents", GHPermissionType.WRITE); permissions.put("metadata", GHPermissionType.READ); GHAppInstallationToken appInstallationToken = appInstallation .createToken(permissions) .create();
Don’t worry about the deprecation warnings, as there is no given alternative. This issue describes the background of this problem.
- Get an installation token, this will authenticate yourself against the organisations auth entity.
GitHub githubAuthAsInst = new GitHubBuilder() .withAppInstallationToken(appInstallationToken.getToken()) .build(); String repositoryName = "...." var repository = githubAuthAsInst.getRepository(organisation+"/"+repositoryName);
The final step involves creating a workflow file to describe what should happen in your repository on a commit. As the workflow file is simply a declarative file of workflow actions, we can simply create a file and commit it to the .github directory.
Create your workflow file as described in this guide. You can adapt it based on what is needed to build your application.
Commit the workflow file to the repository:
String workflowFile = "...." byte workflowFileBytes = Files.asByteSource(new File(workflowFile)).read(); repository.createContent() .content(workflowFileBytes) .path(".github/workflows/maven.yaml") .branch(repository.getDefaultBranch()) .message("setup workflow file") .commit()