7 Commits
0.1.0 ... 0.1.2

Author SHA1 Message Date
66e286f267 fix: Fixes merge conflicts
Some checks failed
CI / Run Tests (push) Failing after 41s
2024-12-18 08:22:18 -05:00
cb25dba7de feat: Updating just file
All checks were successful
CI / Run Tests (push) Successful in 2m52s
2024-12-18 08:15:26 -05:00
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
0c6e9e1228 feat: Bumps version
All checks were successful
CI / Run Tests (push) Successful in 2m19s
2024-12-17 16:02:56 -05:00
faa28749bc feat: Merges dev
All checks were successful
CI / Run Tests (push) Successful in 2m43s
2024-12-17 15:55:36 -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
8 changed files with 46 additions and 99 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 }}

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@ DerivedData/
.swiftpm/* .swiftpm/*
./hpa.toml ./hpa.toml
./Version.* ./Version.*
/*.json

View File

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

View File

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

View File

@@ -15,6 +15,7 @@ public enum HPAKey {
public static let resourceFileExtension = "toml" public static let resourceFileExtension = "toml"
public static let defaultFileName = "config.toml" public static let defaultFileName = "config.toml"
public static let defaultFileNameWithoutExtension = "config" 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] { extension [String: String] {

View File

@@ -1,2 +1,2 @@
// Do not set this variable, it is set during the build process. // Do not set this variable, it is set during the build process.
let VERSION: String? = nil let VERSION: String? = "0.1.1"

View File

@@ -18,6 +18,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json"]) @Test(arguments: ["config.toml", "config.json"])
func generateConfigFile(fileName: String) async throws { func generateConfigFile(fileName: String) async throws {
try await withTestLogger(key: "generateConfigFile") { try await withTestLogger(key: "generateConfigFile") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.coders = .liveValue $0.coders = .liveValue
$0.fileClient = .liveValue $0.fileClient = .liveValue
} operation: { } operation: {
@@ -35,18 +37,6 @@ struct ConfigurationClientTests: TestCase {
#expect(FileManager.default.fileExists(atPath: tempFile.cleanFilePath)) #expect(FileManager.default.fileExists(atPath: tempFile.cleanFilePath))
#expect(fileClient.fileExists(tempFile)) #expect(fileClient.fileExists(tempFile))
#expect(output == tempFile.cleanFilePath) #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]) @Test(arguments: ["config.toml", "config.json", nil])
func loadConfigFile(fileName: String?) async throws { func loadConfigFile(fileName: String?) async throws {
try await withTestLogger(key: "generateConfigFile") { try await withTestLogger(key: "generateConfigFile") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.coders = .liveValue $0.coders = .liveValue
$0.fileClient = .liveValue $0.fileClient = .liveValue
} operation: { } operation: {
@@ -77,6 +69,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"]) @Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
func findConfiguration(fileName: String) async throws { func findConfiguration(fileName: String) async throws {
try await withTestLogger(key: "findConfiguration") { try await withTestLogger(key: "findConfiguration") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue $0.fileClient = .liveValue
} operation: { } operation: {
@Dependency(\.logger) var logger @Dependency(\.logger) var logger
@@ -106,6 +100,8 @@ struct ConfigurationClientTests: TestCase {
@Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"]) @Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"])
func findXdgConfiguration(fileName: String) async throws { func findXdgConfiguration(fileName: String) async throws {
try await withTestLogger(key: "findXdgConfiguration") { try await withTestLogger(key: "findXdgConfiguration") {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue $0.fileClient = .liveValue
} operation: { } operation: {
@Dependency(\.logger) var logger @Dependency(\.logger) var logger
@@ -145,6 +141,8 @@ struct ConfigurationClientTests: TestCase {
@Test @Test
func writeCreatesBackupFile() async throws { func writeCreatesBackupFile() async throws {
try await withDependencies { try await withDependencies {
$0.asyncShellClient = .liveValue
$0.commandClient = .liveValue
$0.fileClient = .liveValue $0.fileClient = .liveValue
} operation: { } operation: {
let client = ConfigurationClient.liveValue let client = ConfigurationClient.liveValue
@@ -152,7 +150,7 @@ struct ConfigurationClientTests: TestCase {
try await withGeneratedConfigFile(named: "config.toml", client: client) { configFile in try await withGeneratedConfigFile(named: "config.toml", client: client) { configFile in
@Dependency(\.fileClient) var fileClient @Dependency(\.fileClient) var fileClient
let backupUrl = configFile.url.appendingPathExtension(".back") let backupUrl = configFile.url.appendingPathExtension("back")
#expect(fileClient.fileExists(backupUrl) == false) #expect(fileClient.fileExists(backupUrl) == false)
let config = Configuration() let config = Configuration()

View File

@@ -2,11 +2,25 @@ docker_image_name := "swift-hpa"
install_path := "~/.local/share/bin/hpa" install_path := "~/.local/share/bin/hpa"
completion_path := "~/.local/share/zsh/completions/_hpa" completion_path := "~/.local/share/zsh/completions/_hpa"
tap_url := "https://git.housh.dev/michael/homebrew-formula"
tap := "michael/formula"
formula := "hpa"
# Build and bottle homebrew formula.
bottle:
@brew uninstall {{formula}} || true
@brew tap {{tap}} {{tap_url}}
@brew install --build-bottle {{formula}}
@brew bottle {{formula}} --json
bottle="$(ls *.gz)" && mv "${bottle}" "${bottle/--/-}"
# Build the command-line tool.
build mode="debug": build mode="debug":
swift build -c {{mode}} swift build -c {{mode}}
alias b := build alias b := build
# Build the docker image.
build-docker file="Dockerfile" tag="latest": build-docker file="Dockerfile" tag="latest":
@docker build \ @docker build \
--file docker/{{file}} \ --file docker/{{file}} \
@@ -14,32 +28,36 @@ build-docker file="Dockerfile" tag="latest":
build-docker-test: (build-docker "Dockerfile.test" "test") build-docker-test: (build-docker "Dockerfile.test" "test")
# Build the docker test image used for testing.
build-docker-test: (build-docker "Dockerfile.test" "test")
# Run tests.
test *ARGS: test *ARGS:
swift test {{ARGS}} swift test {{ARGS}}
alias t := test alias t := test
# Run tests in docker container.
test-docker *ARGS: (build-docker-test) test-docker *ARGS: (build-docker-test)
@docker run --rm \ @docker run --rm \
--network host \ --network host \
{{docker_image_name}}:test \ {{docker_image_name}}:test \
swift test {{ARGS}} swift test {{ARGS}}
# Run the application.
run *ARGS: run *ARGS:
swift run hpa {{ARGS}} swift run hpa {{ARGS}}
alias r := run alias r := run
# Clean the build folder.
clean: clean:
rm -rf .build rm -rf .build
# Bump the version based on the git tag.
update-version: update-version:
@swift package \ @swift package \
--disable-sandbox \ --disable-sandbox \
--allow-writing-to-package-directory \ --allow-writing-to-package-directory \
update-version \ update-version \
hpa hpa
install: (build "release")
@cp .build/release/hpa {{install_path}}
@{{install_path}} --generate-completion-script zsh > {{completion_path}}