3 Commits

Author SHA1 Message Date
9b99b35436 feat: Uses curl to download toml config to allow for pre-built binaries.
Some checks failed
CI / Run Tests (push) Failing after 2m44s
2024-12-17 19:03:16 -05:00
fb246df01a fix: Fixes failing tests since we create backups now during configuration generation.
All checks were successful
CI / Run Tests (push) Successful in 2m43s
CI / Run Tests (pull_request) Successful in 2m22s
2024-12-17 15:44:51 -05:00
0b153d7990 fix: Removes unused release workflow
Some checks failed
CI / Run Tests (push) Failing after 2m52s
CI / Run Tests (pull_request) Failing after 2m15s
2024-12-17 15:32:15 -05:00
5 changed files with 22 additions and 94 deletions

View File

@@ -1,68 +0,0 @@
#
name: Create and publish a Docker image
# Configures this workflow to run every time a change is pushed to the branch called `release`.
on:
push:
branches: ['release']
tags:
- '*'
workflow_dispatch:
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
REGISTRY: git.housh.dev
IMAGE_NAME: ${{ gitea.repository }}
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
attestations: write
id-token: write
#
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.CONTAINER_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
file: docker/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)."
# - name: Generate artifact attestation
# uses: actions/attest-build-provenance@v1
# with:
# subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
# subject-digest: ${{ steps.push.outputs.digest }}
# push-to-registry: true
# github-token: ${{ secrets.CONTAINER_TOKEN }}

View File

@@ -70,6 +70,7 @@ let package = Package(
name: "ConfigurationClient",
dependencies: [
"CodersClient",
"CommandClient",
"FileClient",
.product(name: "Dependencies", package: "swift-dependencies"),
.product(name: "DependenciesMacros", package: "swift-dependencies"),
@@ -114,8 +115,8 @@ let package = Package(
.target(
name: "PlaybookClient",
dependencies: [
"CodersClient",
"CommandClient",
"CodersClient",
"ConfigurationClient",
"FileClient",
.product(name: "Dependencies", package: "swift-dependencies"),

View File

@@ -1,4 +1,5 @@
import CodersClient
import CommandClient
import Dependencies
import DependenciesMacros
import FileClient
@@ -155,6 +156,7 @@ struct LiveConfigurationClient {
private let environment: [String: String]
@Dependency(\.coders) var coders
@Dependency(\.commandClient) var commandClient
@Dependency(\.fileClient) var fileManager
@Dependency(\.logger) var logger
@@ -245,19 +247,13 @@ struct LiveConfigurationClient {
try await fileManager.createDirectory(fileDirectory)
}
// TODO: The hpa file needs to be copied somewhere on the system during install and
// not use bundle, as it only works if the tool was built on the users system.
if case .toml = file {
// In the case of toml, we copy the internal resource that includes
// usage comments in the file.
guard let resourceFile = Bundle.module.url(
forResource: HPAKey.resourceFileName,
withExtension: HPAKey.resourceFileExtension
) else {
throw ConfigurationError.resourceNotFound
}
try await fileManager.copy(resourceFile, fileUrl)
// Copy the file using curl, because when installed as a pre-built binary we
// don't have access to bundled resources.
try await commandClient.run(
quiet: true,
["curl", HPAKey.tomlConfigUrl, "--output", fileUrl.path]
)
} else {
// Json does not allow comments, so we write the mock configuration
// to the file path.

View File

@@ -15,6 +15,7 @@ public enum HPAKey {
public static let resourceFileExtension = "toml"
public static let defaultFileName = "config.toml"
public static let defaultFileNameWithoutExtension = "config"
public static let tomlConfigUrl = "https://git.housh.dev/michael/swift-hpa/raw/branch/main/Sources/ConfigurationClient/Resources/hpa.toml"
}
extension [String: String] {

View File

@@ -18,6 +18,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json"])
func generateConfigFile(fileName: String) async throws {
try await withTestLogger(key: "generateConfigFile") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.coders = .liveValue
$0.fileClient = .liveValue
} operation: {
@@ -35,18 +37,6 @@ struct ConfigurationClientTests: TestCase {
#expect(FileManager.default.fileExists(atPath: tempFile.cleanFilePath))
#expect(fileClient.fileExists(tempFile))
#expect(output == tempFile.cleanFilePath)
// Ensure that we do not overwrite files if they exist.
do {
_ = try await configuration.generate(.init(
force: false,
json: fileName.hasSuffix("json"),
path: .file(File(tempFile)!)
))
#expect(Bool(false))
} catch {
#expect(Bool(true))
}
}
}
}
@@ -54,6 +44,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json", nil])
func loadConfigFile(fileName: String?) async throws {
try await withTestLogger(key: "generateConfigFile") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.coders = .liveValue
$0.fileClient = .liveValue
} operation: {
@@ -77,6 +69,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
func findConfiguration(fileName: String) async throws {
try await withTestLogger(key: "findConfiguration") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue
} operation: {
@Dependency(\.logger) var logger
@@ -106,6 +100,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
func findXdgConfiguration(fileName: String) async throws {
try await withTestLogger(key: "findXdgConfiguration") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue
} operation: {
@Dependency(\.logger) var logger
@@ -145,6 +141,8 @@ struct ConfigurationClientTests: TestCase {
@Test
func writeCreatesBackupFile() async throws {
try await withDependencies {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue
} operation: {
let client = ConfigurationClient.liveValue
@@ -152,7 +150,7 @@ struct ConfigurationClientTests: TestCase {
try await withGeneratedConfigFile(named: "config.toml", client: client) { configFile in
@Dependency(\.fileClient) var fileClient
let backupUrl = configFile.url.appendingPathExtension(".back")
let backupUrl = configFile.url.appendingPathExtension("back")
#expect(fileClient.fileExists(backupUrl) == false)
let config = Configuration()